Skip to content

Add MBTiles file import functionality to offline maps#428

Merged
torlando-tech merged 3 commits intomainfrom
claude/fix-issue-296-pJCIv
Feb 16, 2026
Merged

Add MBTiles file import functionality to offline maps#428
torlando-tech merged 3 commits intomainfrom
claude/fix-issue-296-pJCIv

Conversation

@torlando-tech
Copy link
Copy Markdown
Owner

Summary

This PR adds the ability to import MBTiles files directly into the offline maps feature, complementing the existing download functionality. Users can now select and import MBTiles files from their device storage through a new import button in the top app bar.

Key Changes

  • UI Updates

    • Added a new "FileOpen" icon button to the top app bar for importing MBTiles files
    • Button shows a loading spinner while import is in progress and is disabled during import
    • Updated empty state messaging to mention both download and import options
    • Updated helper text to guide users on how to use both features
  • ViewModel Changes

    • Added importMbtilesFile(uri: Uri) function to handle MBTiles file imports from content URIs
    • Added state tracking for import progress (isImporting) and success messages (importSuccessMessage)
    • Implemented file validation using OfflineMapStyleBuilder.isValidMBTiles()
    • Added automatic filename collision handling with numeric suffixes
    • Integrated with existing OfflineMapRegionRepository.importOrphanedFile() for database registration
  • File Handling

    • Copies imported files to the offline_maps directory
    • Resolves display names from content URIs using ContentResolver
    • Validates MBTiles format before registration
    • Provides user-friendly error messages on import failure
  • Testing

    • Updated UI tests to reflect new empty state messaging

Implementation Details

  • Uses Android's ActivityResultContracts.OpenDocument() for file selection
  • Handles both "application/octet-stream" and wildcard MIME types for broader file picker compatibility
  • Performs file operations on IO dispatcher to avoid blocking the main thread
  • Automatically appends .mbtiles extension if missing
  • Prevents filename collisions by incrementing a counter suffix

https://claude.ai/code/session_014gmo6c1YmbBv1Lvi221nsE

Add the ability to import MBTiles files from external storage via
the system file picker. Users can now tap the import button in the
Offline Maps screen top bar to select an .mbtiles file, which gets
copied to the app's offline_maps directory and registered in the
database with metadata extracted from the file.

https://claude.ai/code/session_014gmo6c1YmbBv1Lvi221nsE
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 9, 2026

Greptile Summary

Added MBTiles file import functionality to offline maps screen. Users can now import map files from device storage via a new FileOpen button in the top app bar.

Key Changes:

  • New import button in top app bar with loading state and proper disabling during import
  • importMbtilesFile() function handles file copying, validation, and database registration
  • Automatic filename collision handling with numeric suffixes
  • Proper error handling with cleanup of orphaned files on failure
  • Integration with existing importOrphanedFile() repository method
  • Updated empty state messaging to guide users on both download and import options
  • Tests updated to reflect new UI text

Implementation Quality:

  • File operations correctly run on IO dispatcher
  • Destination file path resolved before copy operation to ensure cleanup on failure
  • MBTiles validation using OfflineMapStyleBuilder.isValidMBTiles()
  • Proper state management with separate isImporting and importSuccessMessage flows
  • User-friendly snackbar messages for both success and error cases

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • Well-implemented feature with proper error handling, file cleanup on failure, state management, and test coverage. The code has been iteratively improved through multiple commits to handle edge cases like orphaned file cleanup. All file operations use appropriate dispatchers and the implementation integrates cleanly with existing repository methods.
  • No files require special attention

Important Files Changed

Filename Overview
app/src/main/java/com/lxmf/messenger/ui/screens/offlinemaps/OfflineMapsScreen.kt Added import button to top app bar with proper state handling, updated empty state text
app/src/main/java/com/lxmf/messenger/viewmodel/OfflineMapsViewModel.kt Added import functionality with proper file validation, collision handling, and error cleanup
app/src/test/java/com/lxmf/messenger/ui/screens/offlinemaps/OfflineMapsScreenTest.kt Updated test assertions to reflect new empty state text mentioning import

Flowchart

flowchart TD
    A[User clicks import button] --> B[File picker launches]
    B --> C{User selects file?}
    C -->|No| D[Cancel - no action]
    C -->|Yes| E[importMbtilesFile called with URI]
    E --> F[Set isImporting = true]
    F --> G[Resolve destination file path]
    G --> H[Check if filename exists]
    H -->|Exists| I[Append counter suffix]
    I --> H
    H -->|Available| J[Copy file from URI to destination]
    J --> K{Copy successful?}
    K -->|No| L[Catch exception]
    K -->|Yes| M[Validate MBTiles format]
    M -->|Invalid| N[Delete copied file]
    N --> L
    M -->|Valid| O[Register in database via importOrphanedFile]
    O --> P{Registration successful?}
    P -->|No| L
    P -->|Yes| Q[Show success message]
    Q --> R[Set isImporting = false]
    L --> S[Set error message]
    S --> T[Clean up partial file if exists]
    T --> R
    R --> U[End]
    D --> U
Loading

Last reviewed commit: f5be86e

@torlando-tech torlando-tech linked an issue Feb 9, 2026 that may be closed by this pull request
@torlando-tech torlando-tech added this to the v0.9.0 milestone Feb 9, 2026
- Delete the copied MBTiles file in the catch block if DB registration
  via importOrphanedFile() fails, preventing orphaned files on disk
- Replace throw IllegalStateException() with error() to satisfy detekt
  UseCheckOrError rule

https://claude.ai/code/session_014gmo6c1YmbBv1Lvi221nsE
@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Feb 10, 2026

Codecov Report

❌ Patch coverage is 17.04545% with 73 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...m/lxmf/messenger/viewmodel/OfflineMapsViewModel.kt 21.31% 45 Missing and 3 partials ⚠️
...senger/ui/screens/offlinemaps/OfflineMapsScreen.kt 7.40% 25 Missing ⚠️

📢 Thoughts on this report? Let us know!

…cleaned up

Split importMbtilesFile into two withContext blocks: the first resolves
the destination file path (and assigns destFile), the second performs
the copy and validation. Previously, if the copy threw mid-stream,
destFile remained null and the catch block could not delete the partial
file on disk.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@torlando-tech
Copy link
Copy Markdown
Owner Author

@greptileai review

@torlando-tech torlando-tech merged commit 7f7197f into main Feb 16, 2026
10 of 11 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.

Allow external import of map files

2 participants