Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions xftp-web/web/crypto.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const memoryChunks = new Map<number, Uint8Array>()
async function getSessionDir(): Promise<FileSystemDirectoryHandle> {
if (!sessionDir) {
const root = await navigator.storage.getDirectory()
//XFTP behaves more like a real file-transfer system than a database app,
//and OPFS/file handles are much better for large chunked binary file operations.
sessionDir = await root.getDirectoryHandle(SESSION_DIR, {create: true})
}
return sessionDir
Expand Down
1 change: 1 addition & 0 deletions xftp-web/web/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function createProgressRing(): ProgressRing {
const appEl = document.querySelector('[data-xftp-app]') ?? document.getElementById('app')
const s = appEl ? getComputedStyle(appEl) : null
return {
// embedding customization
bg: s?.getPropertyValue('--xftp-ring-bg').trim() || '#e0e0e0',
fg: s?.getPropertyValue('--xftp-ring-fg').trim() || '#3b82f6',
text: s?.getPropertyValue('--xftp-ring-text').trim() || '#333',
Expand Down
15 changes: 12 additions & 3 deletions xftp-web/web/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import {
import {getDescriptionServers, serverOrigin} from '../src/protocol/address.js'
import {XFTPPermanentError} from '../src/client.js'

//Maximum allowed upload size
const MAX_SIZE = 100 * 1024 * 1024
//How much progress bar reserved for encryption phase.
const ENCRYPT_WEIGHT = 0.15
// Only show encryption UI for files large enough to notice.
const ENCRYPT_MIN_FILE_SIZE = 100 * 1024
// Keep encryption progress visible long enough to feel smooth.
const ENCRYPT_MIN_DISPLAY_MS = 1000

export function initUpload(app: HTMLElement) {
Expand Down Expand Up @@ -61,7 +65,7 @@ export function initUpload(app: HTMLElement) {
const copyBtn = document.getElementById('copy-btn')!
const errorMsg = document.getElementById('error-msg')!
const retryBtn = document.getElementById('retry-btn')!

//“ If the browser supports the native Web Share API, dynamically create and insert a Share button and store its reference; otherwise keep it null.”
const shareBtn = typeof navigator.share === 'function'
? (() => {
const btn = document.createElement('button')
Expand All @@ -71,7 +75,7 @@ export function initUpload(app: HTMLElement) {
return btn
})()
: null

//aborted tracks whether the current async upload operation should stop, while pendingFile stores the currently selected file being processed or prepared for upload.
let aborted = false
let pendingFile: File | null = null

Expand All @@ -83,6 +87,8 @@ export function initUpload(app: HTMLElement) {
const f = e.dataTransfer?.files[0]
if (f) startUpload(f)
})

// This app currently supports single file upload
fileInput.addEventListener('change', () => {
if (fileInput.files?.[0]) startUpload(fileInput.files[0])
})
Expand All @@ -92,6 +98,7 @@ export function initUpload(app: HTMLElement) {
showStage(dropZone)
})

//“Hide every application stage, then make only the requested stage visible.”
function showStage(stage: HTMLElement) {
for (const s of [dropZone, progressStage, completeStage, errorStage]) s.hidden = true
stage.hidden = false
Expand Down Expand Up @@ -119,7 +126,9 @@ export function initUpload(app: HTMLElement) {
const ring = createProgressRing()
progressContainer.innerHTML = ''
progressContainer.appendChild(ring.canvas)

//adds the visual progress ring to the page,
// decides whether encryption progress should be shown based on file size,
// reserves part of the progress bar for encryption work, and updates the UI status text accordingly.
const showEncrypt = file.size >= ENCRYPT_MIN_FILE_SIZE
const encryptWeight = showEncrypt ? ENCRYPT_WEIGHT : 0
statusText.textContent = showEncrypt
Expand Down