feat(mobile): Custom Photo Picker with Multi-Select

Resolved 💬 3 comments Opened Dec 25, 2025 by traderose Closed Feb 12, 2026

Problem

The native iOS PHPicker (launched via expo-image-picker) is slow to display photos on the occasion details screen.

Solution

Build a custom in-app photo picker using expo-media-library with FlashList for optimal performance.

Requirements

  • No cropping - Direct selection without edit screen
  • Multi-select - Allow selecting multiple photos at once
  • Progressive thumbnail loading (fast initial display)
  • Album selection (All Photos, Camera Roll, Screenshots, etc.)
  • Camera option still uses fast expo-image-picker

Files to Create

  • mobile/src/components/photo-picker/PhotoPickerSheet.tsx - Main container
  • mobile/src/components/photo-picker/PhotoGrid.tsx - FlashList grid
  • mobile/src/components/photo-picker/PhotoGridItem.tsx - Thumbnails with selection
  • mobile/src/components/photo-picker/AlbumSelector.tsx - Album dropdown
  • mobile/src/components/photo-picker/index.ts - Public exports
  • mobile/src/hooks/useMediaLibrary.ts - Media library hook

Files to Modify

  • mobile/src/components/celebration/MemoryUploadButton.tsx - Use new picker + batch upload
  • mobile/src/components/PhotoUploadButton.tsx - Use new picker
  • mobile/app.config.js - Add expo-media-library plugin
  • mobile/src/locales/*/photoPicker.json - i18n translations (7 languages)

Technical Details

  • Grid: 3 columns, ~110-120px thumbnails
  • Pagination: 50 photos per page with cursor-based pagination
  • Selection: Numbered badges showing selection order
  • Permission flow: Handle granted/limited/denied states

Acceptance Criteria

  • [ ] Custom picker loads faster than native PHPicker
  • [ ] Multi-select works with numbered selection badges
  • [ ] Album switching works
  • [ ] Camera button launches expo-image-picker camera
  • [ ] Works on both iOS and Android
  • [ ] i18n translations for all 7 languages
  • [ ] Unit tests for components

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗