Skip to content

Show real upload percentage (web + native, fula_client 0.6.11)#53

Merged
ehsan6sha merged 1 commit into
mainfrom
feat/upload-progress-ui
Jun 17, 2026
Merged

Show real upload percentage (web + native, fula_client 0.6.11)#53
ehsan6sha merged 1 commit into
mainfrom
feat/upload-progress-ui

Conversation

@ehsan6sha

Copy link
Copy Markdown
Member

Shows a real upload percentage (web + native) instead of the time-based estimate, using the SDK progress API added in fula_client 0.6.11 (functionland/fula-api#43). Bumps fula_client to ^0.6.11 + re-syncs web/pkg.

How it works

The SDK reports real cumulative bytes per content chunk via a pollable handle (createProgressHandle / pollProgress). FulaApiService creates a handle, polls it every 200 ms while the upload future runs, and forwards real bytes to the existing onProgress callback:

  • uploadLargeFileputFlatWithProgress (web).
  • uploadLargeFileResumable / resumeLargeFileUpload*WithProgress (native; a throwaway CancelHandle is synthesized when the caller passed none, since the progress variant requires one).

Polled bytes are capped so the bar never reads 100% before the upload future resolves — the SDK reaches total at the last chunk's PUT, before the index PUT + forest-flush tail. A final onProgress(total, total) fires only after a successful await.

  • Native: sync_service's onProgress now also calls UploadProgressManager.updateProgress(localPath, bytes). UploadProgressState gained an optional bytesUploaded; its percentage prefers real bytes (clamped 0–99) and falls back to the time estimate when the SDK reports nothing.
  • Web: WebUploadManager already maps onProgress.percentage → job.progress, so the tray bar animates with no tray changes.

Caveat (by design)

Small / non-chunked uploads emit no per-chunk events, so their bar stays at 0% until completion (then jumps to 100%) — the time-estimate fallback covers the native path; the web small-file path (uploadObject, ≤768 KB) never had progress. Cosmetic only.

Changes

  • pubspec.yaml / pubspec.lock: fula_client ^0.6.11.
  • web/pkg/: re-synced via tools/sync-wasm-pkg.ps1 to the v0.6.11 flutter-wasm-pkg.zip (VERSION 0.6.11) so the committed wasm matches the pinned SDK and the deploy gate passes.
  • lib/core/models/upload_progress.dart, lib/core/services/{fula_api_service,sync_service,upload_progress_manager}.dart.
  • test/unit/core/models/upload_progress_test.dart (6 tests).

Validation

Verification status

The model + manager have unit tests, but the polling wiring itself (_startProgressPoll → pollProgress → onProgress → tray/manager) has no automated test — it's validated post-deploy:

  • Web (this deploy): a large (multi-chunk, >768 KB) upload on files.fx.land must show intermediate, advancing values (e.g. 0→37→61→…→99→100), not a 0→100 jump. A small (≤768 KB) upload must still complete cleanly (no-event fallback path).
  • Native (iOS/Android/Windows): runtime-unverified here. flutter analyze + the Rust-side E2E don't prove the device path (sync_service → uploadLargeFileResumable → putFlatResumableFromPathWithProgress → poll → updateProgress) actually moves the bar — needs an on-device check when the native app is next built.

🤖 Generated with Claude Code

Replaces the time-based upload estimate with REAL per-chunk progress, using
the polling progress API added in fula_client 0.6.11 (functionland/fula-api#43).

FulaApiService polls the SDK's ProgressHandle every 200ms while an upload
runs and forwards real cumulative bytes to onProgress:
- uploadLargeFile -> putFlatWithProgress (web).
- uploadLargeFileResumable / resumeLargeFileUpload -> *WithProgress (native;
  a throwaway CancelHandle is synthesized when the caller passed none, since
  the progress variant requires one).
Polled bytes are capped so the bar never reads 100% before the upload future
resolves (the SDK reaches total at the last chunk PUT, before the index PUT +
forest-flush tail); a final onProgress(total,total) fires only after success.
Unchanged ticks are skipped so the web tray doesn't repaint needlessly.

- Native: sync_service's onProgress now also calls
  UploadProgressManager.updateProgress(localPath, bytes). UploadProgressState
  gained an optional bytesUploaded; percentage prefers real bytes (clamped
  0-99) and falls back to the time estimate when the SDK reports nothing
  (small / non-chunked uploads emit no per-chunk events).
- Web: WebUploadManager already maps onProgress.percentage -> job.progress,
  so the tray animates with no tray changes.

- pubspec: fula_client ^0.6.11; web/pkg re-synced to the v0.6.11
  flutter-wasm-pkg.zip (VERSION 0.6.11) so the deploy gate passes.
- test: upload_progress_test.dart (6 tests: real-bytes percentage, 99% cap,
  time-estimate fallback, precedence, updateProgress + no-op).

flutter analyze clean (no new issues); model/manager tests green; web build
(main_web.dart) green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ehsan6sha ehsan6sha merged commit 93b4c74 into main Jun 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant