This project delivers a production-ready Android experience for generating AI-enhanced profile photos with Flutter, Firebase, and Google Gemini. The same codebase can be launched on iOS, but iOS builds are considered experimental right now. Expect occasional visual glitches (e.g., notch overlaps, transition flicker) because the design has been optimized for Android phones/tablets. Ship Android; treat iOS as “best effort” until additional QA is performed.
| Stack | Requirement |
|---|---|
| Flutter | 3.24+ with Dart 3.5+ |
| Android | Android Studio Flamingo+, Android SDK 34, USB debugging enabled |
| iOS (optional) | macOS + Xcode 15+ (expect UI issues) |
| Backend | Node.js 20, npm, Firebase CLI (npm i -g firebase-tools) |
| AI | Gemini API key (image generation enabled) |
| Windows-only | Enable Developer Mode (start ms-settings:developers) so Flutter can create plugin symlinks |
- Login & select project
firebase login firebase use <your-project-id>
- Generate platform configs
flutterfire configure --project=<your-project-id> --platforms=android,ios
- Copies
google-services.json+GoogleService-Info.plist - Regenerates
lib/firebase_options.dart
- Copies
- Initialize services (if new project)
firebase init firestore storage functions
- Install Function deps + set Gemini secret
cd functions npm install firebase functions:secrets:set GEMINI_API_KEY # paste your key
Never commit secrets.
android/app/google-services.json,ios/Runner/GoogleService-Info.plist,functions/.runtimeconfig.json,serviceAccount.json,lib/firebase_options.dart,key.properties, keystores (*.keystore,*.jks), certificates (*.pem,*.p12,*.pfx,*.cer,*.mobileprovision), and any*.keys.jsonfiles are ignored via.gitignore. We also ignore generated APKs/AABs so releases are produced per developer. - Deploy backend
npm run build firebase deploy --only functions,firestore:rules,storage cd ..
- Install packages
flutter pub get
- Run on Android
flutter run -d android
- Build release APK
flutter build apk --release
If you ever
flutter cleanandflutter pub get, re-apply theimage_gallery_saverpatch by editing…/image_gallery_saver-2.0.3/android/build.gradleto setcompileSdkVersion 34,namespace, andkotlinOptions.jvmTarget = '17'. - (Optional) Run on iOS
Known issues: tab bars may overlap, launch screen scaling is inconsistent, and some camera/scroll effects flicker. iOS builds are not officially supported yet.
cd ios && pod install && cd .. flutter run -d ios
Create .env in the repo root:
GEMINI_API_KEY=AIza...yourKey...
The Flutter client reads this via flutter_dotenv to fail early when the key is missing (actual calls go through the Cloud Function).
┌─────────┐ ┌────────────┐ ┌─────────────┐ ┌────────────┐
│ Flutter │ ──▶ │ Cloud Func │ ──▶ │ Gemini API │ ──▶ │ Firebase │
└─────────┘ │ (Node/TS) │ │ (image gen) │ │ Storage+DB │
└────────────┘ └─────────────┘ └────────────┘
The app now follows a Single Screen Architecture with a window-like modal system.
| Screen / Component | Responsibilities |
|---|---|
HomeScreen |
The primary orchestrator. Handles image preview, generation flow, and acts as the container for all "window" overlays. Implements a custom PopScope to handle back navigation within the single-screen context. |
SceneSelectionModal |
A pop-out "window" for selecting scenes. Uses a PageView for horizontal sliding of scene options. Supports multi-selection (1-10 scenes) with visual feedback. |
HistoryModal |
A dedicated "window" for browsing all previously generated images. Features a grid layout with edge-to-edge scrolling and full-screen previews. |
FullScreenImageOverlay |
A specialized overlay for viewing images in full detail. Supports pinch-to-zoom (constrained to edges), pan, reset zoom animation, and high-quality downloading. |
ImageSourceModal |
A compact modal for choosing between Camera and Gallery inputs. |
- Multi-Image Generation: Generate 2 to 6 variations at once based on selected scenes.
- Window-Like Experience: Scene selection, History, and Upload flows appear as pop-out windows over the main content, preserving context.
- Smart UI Transitions: Fade-in/out, slide animations, and smooth zoom resets (
Tween<Matrix4>). - Custom Warnings & Errors:
- Scene Limit: Fancy animated dialog when selecting 5+ scenes, with a "Don't show again" option.
- Regeneration: Warning when generating new images would archive current ones.
- Error Handling: Stylish error dialogs with copy-to-clipboard functionality for easier debugging.
- Edge-to-Edge Display: Intelligent image fitting (Cover/Contain) based on orientation to eliminate gray bars.
| Component | Description |
|---|---|
Cloud Function generateProfilePicture |
Callable HTTPS function (Node 20 + TypeScript). Validates auth, downloads original image, calls @google/generative-ai with gemini-2.5-flash-image, uploads generated JPEG to Storage, writes metadata to Firestore, returns signed URL. |
| Firestore | users/{uid} roots session metadata; users/{uid}/results/{resultId} stores prompt, storage paths, signed URL, timestamps. |
| Storage | users/{uid}/original/* for uploads, users/{uid}/generated/* for AI output. |
| Secret Manager | Stores GEMINI_API_KEY. Cloud Function service account has Secret Manager Secret Accessor. |
-
Authentication (Anonymous Firebase Auth)
- The app blocks UI until
ensureAuthProviderresolves. request.auth.uidis required by Firestore, Storage, and the callable Function.
- The app blocks UI until
-
Data Isolation via Rules
match /users/{uid} { allow read, write: if request.auth != null && request.auth.uid == uid; match /results/{resultId} { allow read, write: if request.auth.uid == uid; } }- Storage mirrors the same pattern (
match /users/{uid}/{allPaths=**}).
- Storage mirrors the same pattern (
-
Backend Enforcement
- Cloud Function re-fetches the original file using signed URLs, so clients never touch privileged credentials.
- Only the Function talks to Gemini; the API key lives in Secret Manager.
- MIME type normalization protects Gemini from unsupported
image/jpginputs.
-
Transport & Logging
- All Firebase traffic is HTTPS.
- Errors are surfaced in-app via a custom animated
ErrorDialogwith copy-to-clipboard for support.
-
Platform Caveats
- Android is the reference platform (tested on API 26–34, phones + tablets).
- iOS runs, but due to layout differences you may see navigation bar overlap, misaligned scrollbars, or splash-screen artifacts. Treat iOS as “beta”; file issues before shipping to App Store.
- Windows file locks: If
flutter cleanfails to delete.dart_tool/build, close Android Studio/VS Code terminals or reboot to release handles. - image_gallery_saver patch: Because the plugin is unmaintained, we manually bump its
compileSdkVersionandjvmTarget. If you purge the pub cache, reapply the patch or migrate to a newer gallery saver package. - Logging & debugging:
firebase functions:log --only generateProfilePictureis invaluable when Gemini returns 4xx/5xx errors. Client toast messages intentionally avoid leaking API keys.
Happy building, and remember: Android is rock-solid today; iOS support will come once we iron out the remaining UI glitches. Let us know what you ship! 🎉