A quiz app for creating and taking quizzes, built in Dart/Flutter for Android. Quizzes consist of a text prompt, three wrong answers and one correct answer (all open text). Quizzes can be saved and accessed locally (implemented with SQLite and Floor), or in the cloud (Firebase Data Connect and PostgreSQL). In order to access the cloud features, users must sign up and authenticate (Firebase Auth). This project uses Firebase Emulator rather than a live Firebase project.
- Flutter SDK (stable channel)
- Android Studio with the following SDK tools installed:
- Android SDK Command-line Tools
- Android Emulator
- Node.js (for Firebase CLI)
- Firebase CLI:
npm install -g firebase-tools(for emulator & firebase setup) - Firebase Emulator Downloaded as part of Firebase CLI.
This app uses the Firebase Auth, Data Connect, and Cloud Functions emulators for local development. No live Firebase project is required. Note: the Firebase Installations SDK (a dependency of Cloud Functions) always contacts real Firebase servers; using placeholder credentials will log a warning but the app functions normally for Auth and Data Connect. Cloud Function calls require a valid google-services.json to fully authenticate. Because of this design, there is no need to have a .firebaserc file, and firebase.json only holds emulator-specific data and no API keys.
- Install Flutter dependencies:
flutter pub get- Verify your environment:
flutter doctorAll items should show [✓] before running the app.
- Build the Cloud Functions (required before starting the emulator)
cd functions && npm install && npm run build && cd ..- Start the emulators
From the quiz_app/ directory (where firebase.json lives):
firebase emulators:start --only auth,dataconnect,functions --project demo-quiz-appThe emulator UI will be available at http://127.0.0.1:4000 where you can inspect created accounts and query the local database.
- Configure the app for your mobile emulator or device
Copy local.env.example to local.env and set EMULATOR_HOST for your target:
| Target | EMULATOR_HOST |
|---|---|
| Android emulator (AVD) | 10.0.2.2 |
| Physical device via USB | localhost (see note below) |
| Physical device via Wi-Fi | your Mac's LAN IP (e.g. 192.168.x.x) |
Note — physical device via USB: The Firebase Auth SDK auto-remaps
localhostfor AVDs but Data Connect and Cloud Functions do not. Usingadb reversetunnels all three ports over the USB cable solocalhostworks for everything:~/Library/Android/sdk/platform-tools/adb reverse tcp:9099 tcp:9099 ~/Library/Android/sdk/platform-tools/adb reverse tcp:9399 tcp:9399 ~/Library/Android/sdk/platform-tools/adb reverse tcp:5001 tcp:5001Add
platform-toolsto yourPATH(see below) to useadbdirectly.
Note — Wi-Fi: your device and development machine must be on the same network. Find your Mac's IP with
ipconfig getifaddr en0. Both emulators bind to0.0.0.0so they accept LAN connections.
- Run the app:
flutter run --dart-define-from-file=local.envlocal.env is gitignored so your settings are never committed.
# Add to ~/.zshrc
export PATH="$PATH:$HOME/Library/Android/sdk/platform-tools"Then source ~/.zshrc.
- Create quizzes — add a title, description, optional time limit, and multiple-choice questions
- Take quizzes — timed or untimed, with an immediate score summary on completion
- Rate quizzes — after completing a cloud quiz, rate it 1–5 stars from the results screen
- View past attempts — see score, time taken, and per-question results for each attempt
- Local storage — quizzes and attempts saved to an on-device SQLite database (no account needed)
- Cloud storage — sign in to save quizzes and attempts to Firebase Data Connect (PostgreSQL); cloud attempts are filtered to the signed-in user
- Save toggle — when signed in, the New Quiz page shows a "Save to Cloud" toggle to choose where the quiz is stored
- Username / attribution — set a display name on your Profile; it appears on any cloud quiz you create
- Creator dashboard — the Profile screen doubles as a creator dashboard for signed-in users: it lists every quiz you've published to the cloud and shows, for each quiz, the title, publish date, total number of attempts, average score across all attempts, and average star rating
| Rule | How it's enforced |
|---|---|
| Anyone can read cloud quizzes | @auth(level: PUBLIC) on ListQuizzes and GetQuiz |
| Nobody can modify a quiz after creation | No quiz_update/quiz_delete mutation is exposed to clients |
| Only the author sees their quiz stats | GetMyPublishedQuizzes filters by creatorUserId: { eq_expr: "auth.uid" } server-side |
| Nobody sees each other's attempt results | GetAttemptsForQuiz filters by userId: { eq_expr: "auth.uid" } server-side |
flutter test test/# Android emulator (AVD)
flutter test integration_test/app_test.dart --dart-define=EMULATOR_HOST=10.0.2.2
# Physical device via USB (run adb reverse first — see Setup)
flutter test integration_test/app_test.dart --dart-define=EMULATOR_HOST=localhost -d <device-id># macOS — install lcov first if needed: brew install lcov
flutter test test/ --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.htmlAfter adding or changing methods on QuizRepository or DataConnectQuizRepository, regenerate the Mockito mocks:
dart run build_runner build --delete-conflicting-outputsAfter editing any .gql file under dataconnect/, regenerate the Dart connector:
firebase dataconnect:sdk:generateThese steps confirm the key features work end-to-end with the emulator running.
- Sign up with a new account (drawer → Sign Up)
- Open the drawer → tap Profile
- Enter a display name and tap Save
- Confirm the drawer now shows that name instead of the email address
- Sign in and open the drawer → New Quiz
- Fill in a title, description, and at least one question; enable Save to Cloud
- Tap Save — the app should return to the quiz list
- Confirm the quiz appears in Community Quizzes with a chip showing your username
- To verify the transaction, check the emulator Postgres state at
http://127.0.0.1:4000— the quiz and all its questions should appear together, or neither should appear
- Take any cloud quiz through to completion
- Confirm the results dialog shows a 1–5 star row labelled "Rate this quiz"
- Tap a star — the selection should highlight immediately
- Each attempt lets you submit a new rating; subsequent ratings replace the previous one for your account
- Sign in as the user who created one or more cloud quizzes
- Open the drawer → Profile
- Below the username field, confirm a My Published Quizzes section appears
- For each quiz you published, verify the card shows:
- Quiz title
- Publish date
- Number of attempts
- Average score (as a percentage)
- Average star rating (shown as filled stars)
- Have a second account take one of your quizzes; refresh the Profile screen and confirm the attempt count and average score update
If any of the SQL schema changes, the emulator may crash because of stale data. Clear the emulator's cached Postgres state and restart:
rm -rf dataconnect/.dataconnect
firebase emulators:startBy default, the Auth emulator loses all accounts when stopped. To keep your test accounts between sessions:
# First run — save state on exit
firebase emulators:start --only auth,dataconnect,functions --project demo-quiz-app --export-on-exit=./emulator-data
# Subsequent runs — restore and save
firebase emulators:start --only auth,dataconnect,functions --project demo-quiz-app --import=./emulator-data --export-on-exit=./emulator-dataAdd emulator-data/ to .gitignore to avoid committing it.
Note: If you restart the emulator without
--import, you must sign out and sign back in — the Flutter app caches your token locally but the emulator no longer recognizes it.