Skip to content

Implement Panoramax photo upload and metadata handling - #63

Merged
iamrajeshk merged 9 commits into
aviv-dev-latestfrom
panoramax-implementation
Nov 10, 2026
Merged

iamrajeshk merged 9 commits into
aviv-dev-latestfrom
panoramax-implementation

Conversation

@iamrajeshk

Copy link
Copy Markdown
Collaborator

Replace KartaView with Panoramax for photo uploads

Photos from long form, notes, note comments and Add Feature now go to our own Panoramax instances instead of KartaView. Each photo records the direction the camera faced (bearing) and when it was taken, plus semantic tags so it can be traced back to its element, question and workspace.

What changed

Panoramax upload (PanoramaxApiClient)

  • New client using the upload-set API: create an upload set, upload the files, complete the set. Returns …/api/pictures/<id>/hd.jpg URLs.
  • Each picture is sent with its position, capture time and heading (heading only if known; sending 0 would claim it faces north).
  • Semantic tags added to every picture:
    • all photos: workspace_id
    • tag edits (long form): element_id
    • long form: question, quest_id
    • Add Feature: source=new_feature, feature_type=<preset name> (e.g. Intersection)
    • New nodes get element_id=node/<id> added after the node is uploaded (best effort; failures are only logged).
  • Separate Panoramax instance and token per environment (DEV / STAGE / PROD), including the new PROD instance.
  • Failure handling is unchanged from KartaView: if Panoramax can't be reached, the edit stays unsynced and the rest of the queue keeps uploading.

Photo bearing and capture time for every flow

  • New shared CapturedPhoto(path, bearing, capturedAt) model.
  • New PhotoCapture helper, used by the long form and by AttachPhotoFragment (notes, note comments, Add Feature). It:
    • launches the camera and keeps the pending photo across process death;
    • scales the photo down off the main thread;
    • takes the bearing from the camera's EXIF data, or from the new CameraBearingSensor (back-camera direction, corrected to true north) if the camera didn't write one.
  • Each photo has its own bearing and capture time, including when several are attached to one note or new feature.
  • The capture time sent is when the photo was taken, not when it was uploaded (uploads are deferred, often by hours). Photos without one fall back to the time the edit was made.

OSM tags

  • Long form: the photo URL goes in ext:street_images. An older ext:kartaview_url on the element is still read, and is removed when its photo is replaced or deleted.
  • New nodes: ext:image_url1, ext:image_url2, … (unchanged).

Long form UI

  • An already-uploaded photo shows as a Panoramax thumbnail, falling back to the full image if the thumbnail can't be loaded.

Database (migration 29 → 30)

  • osm_element_edit_photos: photo_questions, photo_quest_ids, photo_captured_at, photo_feature_types
  • `osm_
  • CI and release builds need all three. PROD no longer falls back to the dev token; if the token is missing, uploads fail authentication.

Testing

  • Unit tests: new PanoramaxApiClientTest and PhotoPreviewUrlTest; ElementEditsUploaderTest, NoteEditsUploaderTest, NoteEditsControllerTest, PhotoStateTest and LongFormSubmissionTest were extended. The full unit suite passes.
  • Instrumented tests use MockPanoramax instead of MockKartaView, and RealNetworkGuard blocks real Panoramax hosts.
  • Not covered by unit tests: PhotoCapture / CameraBearingSensor (camera and sensor framework code).

How to verify

  1. Long form: attach a photo, sync, check that ext:street_images is set and the thumbnail shows when the form is reopened.
  2. Note and Add Feature: take 2+ photos facing different directions, sync, and check on Panoramax that each picture has its own heading and capture time, plus the expected semantic tags.
  3. Go offline, take a photo, sync later: the capture time should be when the photo was taken.
  4. Switch between DEV / STAGE / PROD: uploads go to the matching instance.

Notes

  • Testers who installed an earlier build of this branch (already at DB version 30) need to clear app data or reinstall to get the new columns.
  • KartaViewApiClient and its Koin binding are still in the codebase but no longer used for uploads; they can be removed in a follow-up.

…erences, add new API client, and update database schema for photo questions.
…update photo bearing handling to support nullable values and adjust related classes for Panoramax integration.
…mentations, adjust photo handling, and ensure compatibility with new upload logic.
…rePhoto class, and adjust upload logic to include quest_id for long-form questions.
… thumbnails, handle image loading failures, and ensure compatibility with existing photo handling.
…rt for DEV, STAGE, and PROD tokens in build configuration and update related classes for proper token handling.
…clude the time each photo was taken, ensuring accurate timestamps during uploads and database storage.
…ith CapturedPhoto objects to include bearing and capture time, enhancing photo metadata during uploads and storage.
… class and database schema to include feature preset names, enhancing photo metadata during uploads.
@iamrajeshk
iamrajeshk merged commit a05496c into aviv-dev-latest Nov 10, 2026
0 of 3 checks 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