Skip to content

[Frameforge 4] Bridge file import and export to Avalonia and Uno native Open/Save workflows #57

Description

@danwalmsley

Outcome

Audit and complete the browser-to-host file workflow rather than claiming it works because Blob exists. Required for imported sources, portable/reference projects, PNG, SRT/EDL and movie downloads. Playback depends on #54; persistence integration depends on #56; PNG pixels remain owned by #34.

Specification and implementation

  • Audit File/Blob constructors and methods used by the app (size/type/name, text, arrayBuffer, slice), FileReader.readAsDataURL and load/error/abort ordering, URL.createObjectURL/revokeObjectURL, fetch(blob URL), and input[type=file]/FileList/change plus file drag/drop/DataTransfer. Implement missing pieces using immutable/shared byte ownership with cancellation and origin checks.
  • Integrate native picker and download host services with user activation/host policy. Support multiple selection, accept filtering as a picker hint, cancellation and file names; do not silently read arbitrary local paths from script.
  • Implement anchor.download + click for Blob URLs through a real save operation; propagate host cancellation/errors observably and sanitize suggested names. Never declare export successful merely because a URL was created.
  • Support Frameforge portable .frameforge projects (base64-embedded imported files, app limit 250 MiB media / 360 MiB project JSON), reference projects/relinking, still import, SRT import/export and EDL downloads. Preserve original app validation and content; document memory costs and avoid redundant whole-file copies when possible.
  • Blob URL revocation prevents new access while acquired readers/decoders retain valid leases until completion. Ensure navigation, download cancellation and source disposal reclaim storage; add MIME/range support where media consumes Blob resources.

Tests and verification

Round-trip binary files with non-ASCII names, empty/large files and typed-array slices; revoke during decode/download; cross-origin denial; picker/drop cancellation and multiple selection; missing/relinked sources; corrupt portable project and boundary-size failures. Verify saved bytes on disk independently, reload exported project and compare project/media contents. Exercise Native AOT picker callbacks without trimming failures.

Acceptance

  • Original file picker and drag/drop import real local sources without application patches.
  • Portable save/reopen works in a fresh profile; reference relink works and missing media is reported.
  • Downloads contain the expected bytes, cancellation never reports a successful save, and leases do not leak.
  • File/Blob/URL WPT or bounded contracts and host integration regressions pass.

References

File API and HTML download handling.

Original application references

Shared delivery requirements

Parent: #53. Baseline: PR #43 / ce56d49; sample experiments/WebScene.Frameforge.
Reference application: https://github.com/wieslawsoltes/Frameforge (pin f414cd44896b659a5c6da2e4fc596a2ded055f2a, includes demo media and THIRD_PARTY_NOTICES.md).
Implement in WebScene, leaving original application JavaScript/WGSL unchanged. No fake capability objects, synthetic successful events or swallowed errors. Keep public contracts cross-platform with isolated backend implementations; qualify macOS arm64 first and explicitly track Windows/Linux follow-up. Production Avalonia 11 must remain supported; only samples opt into Avalonia 12. Native AOT/trim safety is mandatory.
Add focused native/managed regression coverage and a pinned WPT subset or clearly labeled project-owned contract for non-WebGPU behavior. Applicable WebGPU CTS cases belong with GPU work. Record exact revisions, test commands, negative cases and reproducible evidence in the implementation PR. Unsupported functionality cannot be marked passed; distinguish app coverage from standards conformance. Review existing implementation before adding overlapping infrastructure.

Native application file integration — clarified requirement

WebScene hosts a native application. Browser file APIs are compatibility entry points into native host services; the user-facing action is Open/Import or Save/Save As, not a browser download. This requirement supersedes any browser-download terminology above.

Backend contract

  • Define a backend-neutral asynchronous file interaction service for selecting existing files and selecting/writing a save destination. Supply filename suggestions, allowed file types, multiple-selection intent and owning window; return selected file handles/streams or explicit cancellation. Avoid assuming every provider exposes a local filesystem path.
  • Wire Avalonia to its native storage/file picker integration (StorageProvider OpenFilePickerAsync/SaveFilePickerAsync or the applicable supported API), and Uno to its platform file open/save picker APIs. Resolve picker ownership from the actual hosting window; handle UI-thread dispatch, modal ownership and platform lifecycle requirements in the backend. Inspect existing host abstractions first and extend them rather than adding a sample-only dialog implementation.
  • HTML input[type=file], programmatic activation under the host interaction policy, and supported web picker entry points invoke the native Open dialog. Native file drops feed the same file abstraction and browser File/FileList compatibility objects. Preserve filtering, multiselect and cancellation semantics.
  • Blob + anchor.download/click and supported save-picker APIs invoke the host Save workflow. The compatibility property download supplies a suggested filename; it must not create a browser download shelf, silently choose Downloads, or launch a browser. Use the host-selected destination and normal platform overwrite handling.
  • Write actual exported bytes to the selected native file/stream with bounded asynchronous I/O, proper close/flush and safe replacement where supported. Report write failures through host diagnostics/user feedback and web API promises/events where those APIs define them; do not invent a promise for anchor.click. Cancellation is normal and must not be presented as a saved file.
  • Host configuration may supply an application-specific save destination/workflow, but it must be explicit. Do not silently bypass the native picker or route to a fixed directory. Respect sandbox/security-scoped access and provider lifetime without exposing unrelated filesystem access to JavaScript.
  • Native user-facing wording should say Open, Import, Save or Export. Preserve original Frameforge JavaScript; implement the bridge in WebScene/backend integration. Original web UI text may remain where supplied by the app, but host chrome must behave as native file operations.

Required acceptance on both backends

  • Avalonia and Uno each have a concrete backend implementation and automated contract coverage; unavailable platform hardware is tracked as unverified, not passed.
  • Original Frameforge import opens the actual native Open dialog owned by its window and imports the selected files.
  • Portable project, PNG, SRT/EDL and movie export open a native Save dialog with the appropriate filename/type; selected destination contains independently verified bytes.
  • Cancel, overwrite, permission denial, provider-backed files, write failure and closing the parent during the operation are handled without blocking rendering or leaking streams/handles.
  • Native AOT and production Avalonia 11 support are preserved; sample Avalonia 12 remains an opt-in.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions