A Flutter app for browsing the Art Institute of Chicago's public collection — browse thousands of artworks and save favourites to a personal collection that syncs across devices.
Early work in progress — the roadmap below reflects current state. Built in public.
| Splash | Auth Screen | Email Sign In | Email Sign Up | |
|---|---|---|---|---|
| iOS | ![]() |
![]() |
![]() |
![]() |
| Android | ![]() |
![]() |
![]() |
![]() |
| Layer | Choice | Notes |
|---|---|---|
| Language | Dart / Flutter | iOS & Android |
| State management | BLoC | One bloc per domain — AuthBloc, ArtworkBloc, CollectionBloc |
| Data source | AIC Public API (REST) | CC0, no API key required |
| Auth | Firebase Auth · Google Sign-In | Email/password and Google Sign-In |
Strict BLoC + Repository — no business logic in the UI layer. Each bloc owns one domain and emits states the UI rebuilds from; repositories own all API and Firestore access.
UI (screens / widgets)
↓ events
BLoC AuthBloc · ArtworkBloc · CollectionBloc
↓ calls
Repository ArtRepository (AIC API) · AuthRepository (Firebase) · CollectionRepository (Firestore)
↓
Models plain Dart data classes (Artwork)
Project layout (committed state — UI layer in progress):
lib/
├── main.dart
├── app.dart # MaterialApp
├── firebase_options.dart # generated by flutterfire configure — not committed, see Firebase Setup
├── blocs/
│ ├── auth/ # AuthBloc — events / states
│ ├── artwork/ # ArtworkBloc — fetch, pagination
│ └── collection/ # CollectionBloc — load, save, remove, clear
├── models/
│ └── artwork.dart # fromMap / toMap / imageUrl
├── repositories/
│ ├── art_repository.dart # AIC API — browse
│ ├── auth_repository.dart # Firebase Auth
│ └── collection_repository.dart # Firestore — load, save, remove
├── screens/
│ ├── auth_screen.dart # wired to AuthBloc — sign-in, sign-up, and password reset
│ └── browse_screen.dart # stub — title only
├── theme/
│ ├── app_colors.dart # color tokens
│ ├── app_text_styles.dart # Playfair Display / Barlow Condensed text styles
│ └── app_theme.dart # ThemeData
├── utils/
│ └── app_strings.dart
└── widgets/
└── linen_panel.dart # signature frosted-linen panel — used on Auth, Browse, Detail
-
Artworkmodel — JSON parsing and animageUrlgetter for the AIC IIIF endpoint -
ArtRepository— paginated browse against the AIC API -
ArtworkBloc— fetch and pagination (rolls back on a failed page load) - Firebase Auth —
AuthRepository+AuthBloc(email/password and Google Sign-In) -
CollectionRepository+CollectionBloc - Auth screen UI — landing state (wordmark, Google Sign-In and email buttons)
- Auth screen wired to
AuthBloc(SignInWithGoogle,SignInWithEmail,CreateLoginWithEmail,ResetPasswordevents) - Browse screen — 🚧 In progress (metadata typography + pagination trigger pending)
- Collection screen
- Detail screen — save/unsave wired to Firestore - 🚧 In progress (styling + auth guard pending)
- Polish — empty states, error states
- Tests (
bloc_test)
- Flutter 3.x / Dart 3.x
- VS Code with the Flutter extension
- Android SDK via Android Studio (emulator / device builds)
- Xcode (macOS only — required for iOS simulator and device builds)
- A Firebase project (config files are not committed — see below)
- Create a Firebase project at console.firebase.google.com
- Enable Email/Password and Google Sign-In under Authentication
- Enable Firestore
- Run
flutterfire configureto generatelib/firebase_options.dart - Download
google-services.jsonfrom the Firebase console and place it inandroid/app/ - Download
GoogleService-Info.plistfrom the Firebase console and place it inios/Runner/ - For Google Sign-In on Android: add the SHA-1 fingerprint to your Android app in the Firebase console
git clone https://github.com/eomapps/artexplorer_flutter.git
cd artexplorer_flutter
flutter pub get
flutter runArtwork data and images are provided by the Art Institute of Chicago under CC0 via their public API.







