Skip to content

fix(apple-ui): share-ext prepare phases + clipboard + expiry pill - #8

Merged
MatheusKindrazki merged 2 commits into
mainfrom
fix/share-preparing-phases
Apr 21, 2026
Merged

fix(apple-ui): share-ext prepare phases + clipboard + expiry pill#8
MatheusKindrazki merged 2 commits into
mainfrom
fix/share-preparing-phases

Conversation

@MatheusKindrazki

@MatheusKindrazki MatheusKindrazki commented Apr 21, 2026

Copy link
Copy Markdown
Owner

Três fixes de UX na Share Extension num build:

1. "0% freeze" em uploads grandes

Upload de 125 MB travava a tela por 10-15s antes do progresso mexer — era SHA256 + multipart presign rodando silencioso. Agora cada fase é narrada:

Fase Label Progress bar
hashing "Preparing file…" Determinate 0→100%
presigning "Creating link…" Shimmer
uploading "Uploading… X%" Determinate
finalizing "Finalizing…" Shimmer
  • SHA256Streamer ganhou overload chunked (1 MB) com callback.
  • UploadService novo UploadPreparePhase + prepareObserver. Assinatura legacy preservada.
  • ShareViewModel não atropela fase transient do observer durante poll SwiftData.

2. Link não copiava pro clipboard

copyIfNeeded só flipava o flag visual, sem gravar no pasteboard. Se outro app clobberasse o pasteboard entre /complete e o render do sheet, o user ficava sem link copiado.

Agora copyIfNeeded (single) e BundleSuccessStage.onAppear defensivamente reescrevem UIPasteboard.general.setItems com o shortURL — idempotente sobre o write do orchestrator.

3. Pill "1 hour before it expires" desalinhado

Left-aligned com padding solto e bleeding. Agora é Capsule autofit centrado, ring 16pt, opacity suave.

Test plan

  • FastSharedApp + ShareExt builds OK
  • Vídeo 100+ MB: narração de fases sem 0% parado
  • Link realmente no pasteboard (cole em outro app)
  • Pill centralizado, compacto, bonito

🤖 Generated with Claude Code

…0% freeze"

User reported that uploading a 125 MB video froze the share sheet for
10-15s showing "Uploading… 0%" before the progress actually moved. It
wasn't frozen — SHA-256 hash of the whole file plus multipart presign
was running silently.

Now the UI narrates every phase:

- `.hashing(bytesHashed, totalBytes)` — SHA256Streamer gained a chunked
  overload that calls back every 1 MB. Label: "Preparing file…" with a
  determinate bar from 0 → 100% as the hash advances.
- `.presigning` — emitted right after hash. Label: "Creating link…"
  with an indeterminate shimmer bar (presign + multipart init round-trip).
- `.uploading(progress, …)` — existing, unchanged.
- `.finalizing` — emitted after last R2 PUT, before POST /complete on
  the multipart path. Label: "Finalizing…" with indeterminate shimmer.

UploadService picked up a new `UploadPreparePhase` enum + optional
`prepareObserver` closure on `enqueue`. The protocol is unchanged — the
legacy `enqueue(…)` is now a shim that passes `nil`. Bundle path
untouched (it already had real-time aggregate progress).

ShareViewModel's SwiftData poll (150ms) used to clobber the observer's
pretty label back to `.preparing`; it now respects a transient phase
already set by the observer and only overrides on terminal states.
@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@MatheusKindrazki has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 17 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 54 minutes and 17 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b2293d6-a339-4416-adba-3dd8a02fa523

📥 Commits

Reviewing files that changed from the base of the PR and between aa0aa48 and 700139f.

📒 Files selected for processing (1)
  • apple/FastSharedShareExt/ShareRootView.swift

Walkthrough

O PR introduz rastreamento granular de fases de preparação de upload (hashing, presigning, finalizing) com callbacks de observação, permitindo que a interface de usuário exiba progresso determinado durante hash e progresso indeterminado durante presigning/finalizing através de novos tipos e lógica de renderização aprimorada.

Changes

Cohort / Arquivo(s) Resumo
Serviço de Upload Base
apple/Packages/FastSharedCore/Sources/FastSharedCore/Upload/UploadService.swift, apple/Packages/FastSharedCore/Sources/FastSharedCore/Upload/SHA256Streamer.swift
Novo enum público UploadPreparePhase representa fases pré-PUT/finalize. Novo overload de enqueue(...) aceita prepareObserver opcional e emite eventos de progresso durante hash, presigning e finalizing. SHA256Streamer agora suporta callback de progresso opcional para rastrear bytes processados.
Gerenciamento de Estado da View
apple/FastSharedShareExt/ShareViewModel.swift
Novos casos em ShareUploadPhase: hashing(bytesHashed:totalBytes:), presigning, finalizing. Método applyPreparePhase(_:) mapeia emissões de UploadPreparePhase. Lógica de inicialização preserva fases de preparação em vez de sobrescrever com .preparing.
Controlador e Raiz da View
apple/FastSharedShareExt/ShareViewController.swift, apple/FastSharedShareExt/ShareRootView.swift
ShareViewController.performUpload() passa closure prepareObserver para observar atualizações de fase na MainActor. ShareRootView mapeia novas fases para UI: novo tipo PreparePhaseKind substitui boolean isPreparing, com renderização condicional para barra de progresso (determinada/shimmer) baseada no tipo de preparação.

Sequence Diagram(s)

sequenceDiagram
    participant VC as ShareViewController
    participant US as UploadService
    participant Hasher as SHA256Streamer
    participant VM as ShareViewModel
    participant Root as ShareRootView

    VC->>US: enqueue(..., prepareObserver:)
    US->>VM: prepareObserver(.hashing(0, total))
    VM->>Root: applyPreparePhase(.hashing)
    Root->>Root: render progress UI

    US->>Hasher: hash(fileAt:, progress:)
    Hasher->>Hasher: read chunks (1MB)
    Hasher->>US: progress(bytesHashed)
    US->>VM: prepareObserver(.hashing(N, total))
    VM->>Root: applyPreparePhase(.hashing)
    Root->>Root: update percent + bar

    US->>VM: prepareObserver(.presigning)
    VM->>Root: applyPreparePhase(.presigning)
    Root->>Root: render shimmer bar

    US->>US: await presign responses
    US->>VM: prepareObserver(.finalizing)
    VM->>Root: applyPreparePhase(.finalizing)
    Root->>Root: render finalizing state

    US->>US: complete upload
    VM->>Root: phase = .success
    Root->>Root: render success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutos

Possibly related PRs

Poem

🐰 Preparação em Camadas

Hashing, presigning, finalizando vão,
Cada byte sussurra seu progresso,
Barras brilhantes dançam na ação,
Do upload ao fim, tudo em excesso!
🌟✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título descreve com precisão a mudança principal: introdução de fases granulares de preparação para corrigir a congelamento visual a 0% em uploads grandes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/share-preparing-phases

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Two issues on the success sheet:

1. Link wasn't being copied to clipboard reliably. `copyIfNeeded` only
   flipped the visual `copied` flag — it assumed the orchestrator had
   already written to the pasteboard, which sometimes didn't stick if
   another app clobbered it between /complete and the sheet render.

   Now `copyIfNeeded` (single) and `BundleSuccessStage.onAppear` defensively
   rewrite `UIPasteboard.general.setItems` with the shortURL. Idempotent on
   top of the orchestrator write.

2. "X hour before it expires" pill was left-aligned with loose padding
   and bleeding across the sheet. Tightened: Capsule fill, autofit width,
   center alignment, ring 16pt instead of 24pt, subtler opacity.
@MatheusKindrazki
MatheusKindrazki merged commit 3dd9ccf into main Apr 21, 2026
1 check passed
@MatheusKindrazki
MatheusKindrazki deleted the fix/share-preparing-phases branch April 21, 2026 17:20
@MatheusKindrazki MatheusKindrazki changed the title fix(apple-ui): granular prepare phases — fix 0% freeze on big uploads fix(apple-ui): share-ext prepare phases + clipboard + expiry pill Apr 21, 2026
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