feat: chunked file save + export progress spinner + password-reveal + avatar size
Large file save (fixes black screen on big attachment download / export) - Bridge.saveFile streams anything over ~1MB base64 in chunks through the cmd:// channel instead of stuffing the whole payload in one URL — a multi-MB base64 URL blew past WebView2's ~2MB navigation cap and blanked the document (black screen). Small payloads keep the single-shot path. - Chunks are sent sequentially (each acked via Bridge.onFileChunkAck before the next) so repeated location.href assignments don't coalesce. - Delphi accumulates chunks per reqId in a TStringBuilder (FFileSaveChunks), commits on file/save-commit, and shares the decode+dialog+write logic with the single-shot path via SaveDecodedFile. - Chunk size 1MB → far fewer round-trips (a 20MB export dropped from ~67 to ~27 hops). Busy overlay + progress - Global spinner overlay (showBusy/updateBusy/hideBusy). doExport shows it immediately on click — BEFORE the entry-decrypt + attachment-fetch loop that is the real cost — with a 0ms yield so it paints before the thread blocks (was appearing 3-5s late). Phases: "Reading vault… N/total" → "Encrypting export…" → "Preparing file… N%" (real chunk progress). Attachment download shows the same for files > 512KB. - Spinner ring used an undefined --bg-elev-3 (invalid border → invisible); switched to --border. Fixed a second stale --bg-elev-3 use on the settings-search clear button hover. Password reveal - promptDialog gets an eye toggle in password mode, so every encrypted prompt (export, import, backup password, recovery code, sync password) can show/hide the typed value. Avatar - Top-right chip avatar enlarged 22px → 30px with the chip padding rebalanced. Rebuild: BuildAssets + F9 (UMainForm.pas changed for the chunk handlers). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+34
-7
@@ -741,11 +741,11 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
|
||||
.user-menu { position: relative; }
|
||||
.user-chip {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
padding: 6px 12px;
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
padding: 5px 12px 5px 6px;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
border-radius: 20px;
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
transition: all var(--t-fast);
|
||||
@@ -756,10 +756,10 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
Falls back to a background-image when a custom picture is set. */
|
||||
.user-avatar {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
width: 22px; height: 22px;
|
||||
margin-left: -4px;
|
||||
width: 30px; height: 30px;
|
||||
margin-left: 0;
|
||||
border-radius: 50%;
|
||||
font-size: 11px; font-weight: 600;
|
||||
font-size: 13px; font-weight: 600;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
background-size: cover; background-position: center;
|
||||
@@ -2178,7 +2178,7 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
||||
display: none;
|
||||
}
|
||||
.settings-search-clear svg { width: 12px; height: 12px; }
|
||||
.settings-search-clear:hover { color: var(--text); background: var(--bg-elev-3); }
|
||||
.settings-search-clear:hover { color: var(--text); background: var(--bg-elev-2); }
|
||||
.settings-search-wrap.has-query .settings-search-clear { display: inline-flex; }
|
||||
/* Hidden section + per-row + no-results banner driven by JS. */
|
||||
.slideover-field.is-search-hidden,
|
||||
@@ -2191,6 +2191,33 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
||||
display: none;
|
||||
}
|
||||
.settings-no-results.is-visible { display: block; }
|
||||
/* Global busy overlay — spinner + text for long ops (export, big saves). */
|
||||
.busy-overlay {
|
||||
position: fixed; inset: 0;
|
||||
z-index: 200;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(3px);
|
||||
-webkit-backdrop-filter: blur(3px);
|
||||
}
|
||||
.busy-overlay.is-hidden { display: none; }
|
||||
.busy-box {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 14px;
|
||||
padding: 24px 32px;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.busy-spinner {
|
||||
width: 34px; height: 34px;
|
||||
border: 3px solid var(--border);
|
||||
border-top-color: var(--accent);
|
||||
border-radius: 50%;
|
||||
animation: busy-spin 0.7s linear infinite;
|
||||
}
|
||||
@keyframes busy-spin { to { transform: rotate(360deg); } }
|
||||
.busy-text { font-size: 13px; color: var(--text-dim); text-align: center; }
|
||||
.slideover-field-label { font-size: 11px; font-weight: 500; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
|
||||
.slideover-field-value {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
|
||||
Reference in New Issue
Block a user