Add mobile photo capture with client-side image downscaling - #249
Open
canni wants to merge 5 commits into
Open
Conversation
Root cause: the camera change handler assigned cameraInput.files to the named input directly - both inputs then shared ONE FileList object, and the cameraInput.value = '' reset on the next line emptied that shared list, so the photo was gone before submit. Copying through a new DataTransfer decouples the two inputs while keeping the synchronous no-async-gap population.
…d service worker)
- capability-gate the Take Photo button when DataTransfer is unavailable (hide it rather than fail silently after the user takes a photo) - normalize empty-MIME camera captures to image/jpeg so previews render - pass animated GIFs through untouched instead of flattening to JPEG - make camera labels keyboard-operable (tabindex + Enter/Space) - dedupe the DataTransfer copy into trySetFiles; single camera-input reset - drop the redundant generation counter (files[0] identity check subsumes it) and the duplicated listener-level MIME check - mark pass-through files in the WeakSet to skip re-decoding on re-fired events - free the full-res bitmap before JPEG encode and release the canvas store - document the double-fire change-event contract at both dispatch sites - index.html: Choose Photo icon fa-camera -> fa-upload (match status.html) - bump asset version to 20260719002
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I run Warracker on my home server and it replaced my own warranty tracker app, but the one thing that kept bugging me was adding receipts from the phone. Right after a purchase you want to snap the receipt and be done, instead the flow was: open camera app, take photo, remember to resize it (phone photos are 8-15MB, easy to hit MAX_UPLOAD_MB), upload through the file picker, then go delete the receipt from the gallery. This PR fixes that whole path.
What it does:
<input accept="image/*" capture="environment">, so on mobile the camera opens directly and the photo never lands in the galleryImplementation notes:
warranties.take_photoadded to all 20 locale filesTesting: this exact branch (well, the same commits on a 1.0.2 base) has been running on my own instance for a few days with real phone use, and I have a Playwright harness that drives both the add and edit flow headless against a docker compose stack, asserting the photo actually lands in the DB downscaled. Happy to share the harness script if you want it in the repo.
Known limitation: if someone picks a file the browser can't decode (e.g. HEIC on a non-Safari desktop) it passes through unconverted and the backend rejects the extension, same as today. In practice camera captures are always JPEG so this doesn't bite on the main path.
Your contributing notes say to discuss in an issue first, sorry for jumping straight to code, this started as a patch for my own instance and grew into something shareable. Happy to split or rework whatever doesn't fit, e.g. if you'd rather have this in the frontend/js component layer I can move it there.