Screens and ViewModels

Every feature screen in Scanly v1.0.17 and its responsibilities.

Screen inventory

FeatureScreenViewModelRoutePrimary responsibilities
OnboardingOnboardingScreenOnboardingViewModel(gate in MainActivity)First-run intro; persist completion
HomeHomeScreenHomeViewModelhomeRecent paper cards, scan/import/folder, suggest names, library shortcut
Widgets / shortcuts(system chrome)LaunchActionViewModelvia MainActivity intentsScan, Import, QR, Library redirects
LibraryLibraryScreenLibraryViewModellibraryPaper cards, overflow/long-press actions, search, filter pills, sort, CRUD, suggest names
Tools hubToolsScreenToolsViewModeltoolsScan / PDF / Utilities groups; QR opens straight into scanning
QR toolQrToolScreen (+ QrScanScreen, QrResultScreen, QrCreateScreen, QrHistoryScreen)QrToolViewModeltools/qrScan with torch and photo import, typed results, Create types with caption and ink, on-phone history
PDF readerPdfReaderRoutePdfReaderViewModeltools/pdf/readerPicker step, dark reader with one page counter, hideable chrome, Pages grid, Layout, Share
PDF mergePdfMergeRoutePdfMergeViewModeltools/pdf/mergeMulti-select picker → order & name → done
PDF compressPdfCompressRoutePdfCompressViewModeltools/pdf/compressPicker → quality → working → done with saving and before/after
PDF passwordPdfPasswordRoutePdfPasswordViewModeltools/pdf/passwordPicker → Add password (strength, restrict editing) or Remove password, chosen by the file → done
PDF watermarkPdfWatermarkRoutePdfWatermarkViewModeltools/pdf/watermarkPicker → editor with pinned live preview (presets, date, style, colour, pages) → done
Group detailGroupDetailScreenGroupDetailViewModelgroup/{groupId}Membership, rename, delete, group export, create doc in group
Document detailDocumentDetailScreenDocumentDetailViewModeldocument/{documentId}Portrait page tiles, tap-to-review, long-press reorder, rename, import, export/save, move to group
Scan sessionScanSessionScreenScanSessionViewModelcamera/session/{docId}Camera permission (ask first), CameraX, gate + multi-model overlay, stability, auto-capture, finalize
Page previewPageImagePreviewScreenPageImagePreviewViewModelpreview/page/{pageId}Image-only paging, zoom, share/edit/retake/delete overflow
Page editorPageEditorScreenPageEditorViewModeleditor/page/{pageId}Opens filter/adjust/crop; retake, delete
Filter pickerFilterPickerScreen(shares PageEditorViewModel)(editor overlay)Full-screen live preview + preset chips
Filter adjustFilterCustomizeScreen(shares PageEditorViewModel)(editor overlay)Brightness/contrast/saturation/sharpness sliders
Page cropPageCropScreenPageCropViewModelcrop/page/{pageId}AI detect, rotate, four-point crop handles, reset, apply
SettingsSettingsScreenSettingsViewModelsettingsLook & feel, document detection, links, manual update check
Storage & backupStorageBackupScreenSettingsViewModelsettings/storageDestination, usage, backup/restore progress, clear data
Model benchmarkModelBenchmarkRouteModelBenchmarkViewModelsettings/model-benchmarkPer-image overview with polygon overlays on scaled previews for each corner model, plus gate/pipeline stats
FAQsSettingsFaqScreenSettingsViewModelsettings/faqBundled FAQ content
LicensesSettingsLicensesScreenSettingsViewModelsettings/licensesThird-party license list
LegalLegalDocumentScreen—legal/{documentType}Privacy / terms WebView content
App updateAppUpdateDialogAppUpdateViewModel(overlay)Channel-specific update check, cooldown
Flexible updateFlexibleUpdateSnackbarAppUpdateViewModel(overlay)Restart prompt after Play flexible download
PlaceholderFeaturePlaceholderScreen—camera, review, editorLegacy stubs — do not extend

App-level ViewModels

Hosted in MainActivity, not tied to a single screen:

ViewModelRole
AppSettingsViewModelObserves theme mode and pure black preference globally
OnboardingViewModelTracks onboarding completion state
AppUpdateViewModelAutomatic and manual update checks; dialog and snackbar state

ViewModel → use case mapping (key screens)

HomeViewModel

  • ObserveRecentDocumentsUseCase, ObserveRecentGroupsUseCase
  • CreateDocumentUseCase, CreateGroupUseCase
  • SuggestDocumentTitleUseCase, SuggestGroupTitleUseCase
  • ImportImagesUseCase

LibraryViewModel

  • ObserveDocumentsUseCase, ObserveGroupsUseCase, ObserveUngroupedDocumentsUseCase
  • CreateDocumentUseCase, DeleteDocumentUseCase, RenameDocumentUseCase
  • CreateGroupUseCase, DeleteGroupUseCase, RenameGroupUseCase
  • SuggestDocumentTitleUseCase, SuggestGroupTitleUseCase

DocumentDetailViewModel

  • ObserveDocumentUseCase, ObserveDocumentPagesUseCase
  • RenameDocumentUseCase, DeletePageUseCase, MovePageUseCase
  • SetDocumentGroupUseCase, ImportImagesUseCase, SuggestGroupTitleUseCase
  • ExportDocumentPdfUseCase, ExportDocumentImageArchiveUseCase
  • SaveExportArtifactUseCase
  • PrepareDocumentPdfShareUseCase, PrepareDocumentImageShareUseCase

ScanSessionViewModel

  • PreparePageCaptureUseCase, PrepareReplacementCaptureUseCase
  • FinalizeCapturedPageUseCase
  • Observes live model / automatic selection / document gate preferences
  • Uses DocumentGateDetector, DocumentCornerDetector, StableCornerSelector, DocumentGateStabilityTracker, and CaptureStabilityTracker for live overlay and auto-capture

PageEditorViewModel

  • ObservePageUseCase, UpdatePageEditsUseCase, DeletePageUseCase
  • Filter preset + per-page adjustments (brightness/contrast/saturation/sharpness) and page delete; adopts crop/rotation updates after the crop screen applies

PageCropViewModel

  • ObservePageUseCase, UpdatePageEditsUseCase, DetectDocumentCornersUseCase
  • Uses CropQuadEditor for rotation, interactive crop handles, and session reset
  • AI Detect runs still-image corner detection (same post-processing path as capture)

PageImagePreviewViewModel

  • ObservePageUseCase, ObserveDocumentPagesUseCase
  • DeletePageUseCase
  • Share uses processed image path via FileProvider

GroupDetailViewModel

  • ObserveGroupUseCase, ObserveGroupDocumentsUseCase
  • RenameGroupUseCase, DeleteGroupUseCase, SetDocumentGroupUseCase
  • SuggestDocumentTitleUseCase, CreateDocumentUseCase
  • ExportGroupPdfUseCase, ExportGroupZippedPdfsUseCase
  • PrepareGroupPdfShareUseCase, PrepareGroupZippedPdfsShareUseCase
  • SaveExportArtifactUseCase

SettingsViewModel

  • ObserveThemeModeUseCase, SetThemeModeUseCase
  • ObservePureBlackEnabledUseCase, SetPureBlackEnabledUseCase
  • Live / post model observe+set, automatic selection, document gate use cases
  • LoadSettingsContentUseCase, GetAppStorageUsageUseCase
  • ObserveExportDestinationUseCase, SetExportDestinationUseCase, ResetExportDestinationUseCase
  • EstimateLibraryBackupUseCase, StartLibraryBackupUseCase, StartLibraryRestoreUseCase
  • ObserveLibraryArchiveWorkUseCase, CancelLibraryArchiveWorkUseCase
  • ClearAllAppDataUseCase
  • AutomaticDocumentModelSelector for calibrated automatic picks
  • Triggers AppUpdateViewModel.checkForUpdates(Manual)

ModelBenchmarkViewModel

  • Injects DocumentCornerDetector and DocumentGateDetector directly for temporary local runs
  • Does not share SettingsViewModel (results are ephemeral)

Shared UI components

feature/components/:

FilePurpose
SharedComponents.ktPaper document/group cards, overflow/long-press actions, thumbnails
FabComponents.ktFAB menus for create/scan/import
ExportShareComponents.ktExport and share bottom sheets

core/ui/:

FilePurpose
ScanlyChrome.ktTop bars, shared chrome
ThumbnailCache.ktIn-memory thumbnail cache
PreviewImageSizer.ktConsistent preview dimensions
ImageImportSupport.ktGallery picker (10 image limit)
AdaptiveLayout.ktPhone vs tablet / width-class helpers
ZoomableImageDialog.ktPinch-zoom preview (document detail)
ZoomableImageViewer.ktPinch-zoom viewer (page preview)

Large-screen editor layout

On tablet landscape (and other wide landscape windows that opt into tool two-pane), editor flows share EditorLandscapeChrome:

ScreenLeft paneRight pane
Page editorLive cropped previewVertical tool rail (Crop, Filters, Adjust, Retake, Delete)
Page cropInteractive crop canvasVertical rail (AI Detect, rotate, reset)
FiltersLive filter previewScope switch + 2-column preset grid
AdjustLive adjusted previewScrollable sliders

Phone portrait keeps the stacked preview-above-controls layout.

Editor package helpers (feature/editor/):

FileRole
EditorImageSupport.ktLive preview: decode, crop, filter, adjustments
EditorScrollbars.ktShared vertical scrollbar for Filters/Adjust panes
FilterPickerScreen.ktFull-screen filter preset picker
FilterCustomizeScreen.ktFull-screen filter fine-tuning
PageCropScreen.kt / PageCropViewModel.ktDedicated crop route

Scan session internals

Classes supporting ScanSessionScreen (not separate screens):

ClassRole
CaptureFrameQualityAnalyzerLighting, blur, obstruction feedback
CaptureStabilityTrackerAuto-capture phase machine (AutoCapturePhase); worst-corner motion
DocumentGateStabilityTrackerRequires consecutive accepted gate frames before corners run
StableCornerSelectorRank, confirm, and smooth the visible outline
CameraOverlayMapperMaps ML quad to overlay coordinates

View source on GitHub · Markdown