File Storage

Scanly stores document images in app-private directories managed by AppPrivateDocumentStorageManager (data/storage/).

Image paths referenced in Room entities point to files under these directories. The database stores metadata; the filesystem stores pixels.

Per-document layout

files/documents/{documentId}/
├── raw/
│   └── page_001.jpg, page_002.jpg, …    # Immutable captures
├── processed/
│   └── page_001.jpg, page_002.jpg, …    # Derived corrected/filtered output
└── thumbs/
    ├── cover.jpg                         # Document cover thumbnail
    └── page_001.jpg, page_002.jpg, …     # Page list thumbnails
DirectoryMutabilityPurpose
raw/ImmutableOriginal camera capture or imported image
processed/Regenerated on editPerspective-corrected, filtered JPEG
thumbs/Regenerated on editSmall previews for lists and covers

Design rules

  1. Never overwrite raw files. Edits call reprocessPage, which reads from raw/ and writes new processed/ and thumbs/ paths.
  2. Paths in Room are authoritative. Repositories update entity path columns after every write.
  3. Document root is stored in DocumentEntity.rootDirectoryPath for cleanup and migration.

App-private working directories

PathPurpose
cache/library-archive/Restore staging workspace
files/library-archive-journal/Durable restore recovery journal
databases/scanly.db (+ -wal, -shm)Room database

Export cache

Ephemeral export artifacts live outside document directories:

cache/exports/{documentId}/     # Single-document PDF or ZIP
cache/exports/group_{groupId}/  # Group merged PDF or zipped PDFs

Export cache can be cleared without losing library data. It is included in storage usage reporting and wiped by clear-all-data.

User-visible exports and backups

Generated cache artifacts are copied to shared storage when the user chooses Save:

Downloads/Scanly/                 # Default direct-save destination
└── backup/                       # Reserved for .scanly backups

A Storage Access Framework tree selected in Settings replaces Downloads/Scanly as the base. Normal exports use the base; Scanly creates and manages its lowercase backup child. Persisted access is required, existing names receive numeric suffixes, and partial writes are removed after failure or cancellation.

.scanly is a ZIP container with a versioned manifest, entity metadata, exact raw/processed/thumbnail assets, sizes, and SHA-256 checksums. Settings, export cache, SQLite files, and previous backups are excluded.

Thumbnail cache

ThumbnailCache (core/ui/) maintains an in-memory cache of decoded thumbnails for fast list scrolling. Invalidated when:

  • A page is reprocessed
  • A document cover changes
  • Clear-all-data runs

Capture path allocation

Before capture or import:

  1. PageRepository.prepareCapture or prepareReplacementCapture allocates the next raw/page_NNN.jpg path.
  2. Camera or gallery writes the raw JPEG to that path.
  3. finalizeCapture runs processing and writes processed/ and thumbs/.

Image format settings

Processed JPEG output (from PageImageProcessor):

Storage usage reporting

GetAppStorageUsageUseCase → DefaultAppDataRepository reports:

CategoryWhat it measures
DocumentsAll files under files/documents/
Export cacheAll files under cache/exports/
Databasescanly.db file size
Archive workspaceRestore staging and recovery journals

Displayed in Settings via StorageFormatter.

Clear all data

ClearAllAppDataUseCase performs a full wipe:

  1. database.clearAllTables() — all Room records
  2. Delete every directory under files/documents/
  3. Delete cache/exports/
  4. thumbnailCache.clearAll()
  5. Delete backup/restore workspace files; completed external .scanly backups are kept

Destructive and irreversible. Requires user confirmation in Settings.

View source on GitHub · Markdown