├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── Runner.entitlements
│ ├── AppDelegate.swift
│ ├── GoogleService-Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ ├── flutter_export_environment.sh
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── Podfile
└── Podfile.lock
├── lib
├── services
│ ├── services.dart
│ ├── firestore.dart
│ ├── models.dart
│ ├── auth.dart
│ └── models.g.dart
├── shared
│ ├── shared.dart
│ ├── error.dart
│ ├── loading.dart
│ ├── bottom_nav.dart
│ └── progress_bar.dart
├── about
│ └── about.dart
├── routes.dart
├── theme.dart
├── quiz
│ ├── quiz_state.dart
│ └── quiz.dart
├── home
│ └── home.dart
├── main.dart
├── topics
│ ├── topics.dart
│ ├── topic_item.dart
│ └── drawer.dart
├── profile
│ └── profile.dart
└── login
│ └── login.dart
├── assets
├── logo.png
├── user.png
├── congrats.gif
└── covers
│ ├── js.png
│ ├── rxjs.png
│ ├── ts.png
│ ├── angular.png
│ ├── firebase.png
│ ├── firestore.png
│ ├── flutter.png
│ ├── default-cover.png
│ ├── flutter-layout.png
│ └── cloud-functions.png
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── quizapp3
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ └── google-services.json
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── .metadata
├── .gitignore
├── README.md
├── analysis_options.yaml
├── pubspec.yaml
├── .flutter-plugins-dependencies
└── pubspec.lock
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/services/services.dart:
--------------------------------------------------------------------------------
1 | export 'auth.dart';
2 | export 'firestore.dart';
3 | export 'models.dart';
4 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/logo.png
--------------------------------------------------------------------------------
/assets/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/user.png
--------------------------------------------------------------------------------
/assets/congrats.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/congrats.gif
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/assets/covers/js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/js.png
--------------------------------------------------------------------------------
/assets/covers/rxjs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/rxjs.png
--------------------------------------------------------------------------------
/assets/covers/ts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/ts.png
--------------------------------------------------------------------------------
/assets/covers/angular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/angular.png
--------------------------------------------------------------------------------
/assets/covers/firebase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/firebase.png
--------------------------------------------------------------------------------
/assets/covers/firestore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/firestore.png
--------------------------------------------------------------------------------
/assets/covers/flutter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/flutter.png
--------------------------------------------------------------------------------
/lib/shared/shared.dart:
--------------------------------------------------------------------------------
1 | export 'bottom_nav.dart';
2 | export 'error.dart';
3 | export 'loading.dart';
4 | export 'progress_bar.dart';
5 |
--------------------------------------------------------------------------------
/assets/covers/default-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/default-cover.png
--------------------------------------------------------------------------------
/assets/covers/flutter-layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/flutter-layout.png
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/assets/covers/cloud-functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/assets/covers/cloud-functions.png
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/quizapp3/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.fireship.quizapp
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireship-io/flutter-firebase-quizapp-course/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/Runner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.applesignin
6 |
7 | Default
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: ffb2ecea5223acdd139a5039be2f9c796962833d
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/lib/shared/error.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ErrorMessage extends StatelessWidget {
4 | final String message;
5 |
6 | const ErrorMessage({super.key, this.message = 'it broke'});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Center(
11 | child: Text(message),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/lib/about/about.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AboutScreen extends StatelessWidget {
4 | const AboutScreen({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Scaffold(
9 | appBar: AppBar(title: const Text('about'), backgroundColor: Colors.blue),
10 | body: const Center(
11 | child: Text('About this app...'),
12 | ),
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:quizapp/about/about.dart';
2 | import 'package:quizapp/profile/profile.dart';
3 | import 'package:quizapp/login/login.dart';
4 | import 'package:quizapp/topics/topics.dart';
5 | import 'package:quizapp/home/home.dart';
6 |
7 | var appRoutes = {
8 | '/': (context) => const HomeScreen(),
9 | '/login': (context) => const LoginScreen(),
10 | '/topics': (context) => const TopicsScreen(),
11 | '/profile': (context) => const ProfileScreen(),
12 | '/about': (context) => const AboutScreen(),
13 | };
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=C:\src\flutter"
4 | export "FLUTTER_APPLICATION_PATH=D:\dev\flutter-firebase-quizapp-course"
5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true"
6 | export "FLUTTER_TARGET=lib\main.dart"
7 | export "FLUTTER_BUILD_DIR=build"
8 | export "FLUTTER_BUILD_NAME=1.0.0"
9 | export "FLUTTER_BUILD_NUMBER=1"
10 | export "DART_OBFUSCATION=false"
11 | export "TRACK_WIDGET_CREATION=false"
12 | export "TREE_SHAKE_ICONS=false"
13 | export "PACKAGE_CONFIG=.dart_tool/package_config.json"
14 |
--------------------------------------------------------------------------------
/lib/shared/loading.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Loader extends StatelessWidget {
4 | const Loader({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const SizedBox(
9 | width: 250,
10 | height: 250,
11 | child: CircularProgressIndicator(),
12 | );
13 | }
14 | }
15 |
16 | class LoadingScreen extends StatelessWidget {
17 | const LoadingScreen({super.key});
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return const Scaffold(
22 | body: Center(
23 | child: Loader(),
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/ephemeral/
22 | Flutter/app.flx
23 | Flutter/app.zip
24 | Flutter/flutter_assets/
25 | Flutter/flutter_export_environment.sh
26 | ServiceDefinitions.json
27 | Runner/GeneratedPluginRegistrant.*
28 |
29 | # Exceptions to above rules.
30 | !default.mode1v3
31 | !default.mode2v3
32 | !default.pbxuser
33 | !default.perspectivev3
34 |
--------------------------------------------------------------------------------
/lib/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 |
4 | var appTheme = ThemeData(
5 | fontFamily: GoogleFonts.nunito().fontFamily,
6 | bottomAppBarTheme: const BottomAppBarTheme(
7 | color: Colors.black87,
8 | ),
9 | brightness: Brightness.dark,
10 | textTheme: const TextTheme(
11 | bodyText1: TextStyle(fontSize: 18),
12 | bodyText2: TextStyle(fontSize: 16),
13 | button: TextStyle(
14 | letterSpacing: 1.5,
15 | fontWeight: FontWeight.bold,
16 | ),
17 | headline1: TextStyle(
18 | fontWeight: FontWeight.bold,
19 | ),
20 | subtitle1: TextStyle(
21 | color: Colors.grey,
22 | ),
23 | ),
24 | buttonTheme: const ButtonThemeData(),
25 | );
26 |
--------------------------------------------------------------------------------
/lib/quiz/quiz_state.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:quizapp/services/models.dart';
3 |
4 | class QuizState with ChangeNotifier {
5 | double _progress = 0;
6 | Option? _selected;
7 |
8 | final PageController controller = PageController();
9 |
10 | double get progress => _progress;
11 | Option? get selected => _selected;
12 |
13 | set progress(double newValue) {
14 | _progress = newValue;
15 | notifyListeners();
16 | }
17 |
18 | set selected(Option? newValue) {
19 | _selected = newValue;
20 | notifyListeners();
21 | }
22 |
23 | void nextPage() async {
24 | await controller.nextPage(
25 | duration: const Duration(milliseconds: 500),
26 | curve: Curves.easeOut,
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.8'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | project.evaluationDependsOn(':app')
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/lib/home/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:quizapp/login/login.dart';
3 | import 'package:quizapp/services/auth.dart';
4 | import 'package:quizapp/shared/shared.dart';
5 | import 'package:quizapp/topics/topics.dart';
6 |
7 | class HomeScreen extends StatelessWidget {
8 | const HomeScreen({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return StreamBuilder(
13 | stream: AuthService().userStream,
14 | builder: (context, snapshot) {
15 | if (snapshot.connectionState == ConnectionState.waiting) {
16 | return const LoadingScreen();
17 | } else if (snapshot.hasError) {
18 | return const Center(
19 | child: ErrorMessage(),
20 | );
21 | } else if (snapshot.hasData) {
22 | return const TopicsScreen();
23 | } else {
24 | return const LoginScreen();
25 | }
26 | },
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Firebase - The Full Course 3.0
2 |
3 | 🕊️🔥 Build a realtime Quiz App from scratch with Flutter 3 & Firebase.
4 |
5 | ## Learn it
6 |
7 | Enroll in the [Flutter Firebase Course](https://fireship.io/courses/flutter-firebase/) on Fireship.
8 |
9 | ## Try it
10 |
11 | - [Get it on The App Store](https://itunes.apple.com/us/app/fireship/id1462592372?mt=8)
12 | - [Get it on Google Play](https://play.google.com/store/apps/details?id=io.fireship.quizapp)
13 |
14 | ## Run it
15 |
16 | ```
17 | git clone https://github.com/fireship-io/flutter-firebase-quizapp-course.git quizapp
18 | cd quizapp
19 |
20 | flutter run
21 | ```
22 |
23 | ## Learning Goals
24 |
25 | - 👨🎤 Build a complete Flutter app with Firebase
26 | - 🐦 Master most common Flutter widgets
27 | - 🔏 User Authentication (Apple, Google, Anonymous)
28 | - ⚒️ State Management with Provider
29 | - 🔥 Model relational Firestore data
30 | - 🎭 Animation for realtime data streams
31 | - ⚓ Organize large Flutter projects
32 | - 🤖 Firestore -> Dart Classes with JSON Serializable
33 | - 🚀 Deploy to the Apple App Store and Google Play
34 |
--------------------------------------------------------------------------------
/lib/shared/bottom_nav.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
3 |
4 | class BottomNavBar extends StatelessWidget {
5 | const BottomNavBar({super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return BottomNavigationBar(
10 | items: const [
11 | BottomNavigationBarItem(
12 | icon: Icon(
13 | FontAwesomeIcons.graduationCap,
14 | size: 20,
15 | ),
16 | label: 'Topics',
17 | ),
18 | BottomNavigationBarItem(
19 | icon: Icon(
20 | FontAwesomeIcons.bolt,
21 | size: 20,
22 | ),
23 | label: 'About',
24 | ),
25 | BottomNavigationBarItem(
26 | icon: Icon(
27 | FontAwesomeIcons.circleUser,
28 | size: 20,
29 | ),
30 | label: 'Profile',
31 | ),
32 | ],
33 | fixedColor: Colors.deepPurple[200],
34 | onTap: (int idx) {
35 | switch (idx) {
36 | case 0:
37 | // do nothing
38 | break;
39 | case 1:
40 | Navigator.pushNamed(context, '/about');
41 | break;
42 | case 2:
43 | Navigator.pushNamed(context, '/profile');
44 | break;
45 | }
46 | },
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ios/Runner/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 758773997881-sk4tfalbk1oqh5f2vv4gbcjqdlm7lq5f.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.758773997881-sk4tfalbk1oqh5f2vv4gbcjqdlm7lq5f
9 | ANDROID_CLIENT_ID
10 | 758773997881-b4g2gerk1isv5ehq4h9s63hgnn433rjc.apps.googleusercontent.com
11 | API_KEY
12 | AIzaSyCHpFJY54w_YiXjCOfbVbsefn91FFUJ9PE
13 | GCM_SENDER_ID
14 | 758773997881
15 | PLIST_VERSION
16 | 1
17 | BUNDLE_ID
18 | io.fireship.quizapp
19 | PROJECT_ID
20 | fireship-lessons
21 | STORAGE_BUCKET
22 | fireship-lessons.appspot.com
23 | IS_ADS_ENABLED
24 |
25 | IS_ANALYTICS_ENABLED
26 |
27 | IS_APPINVITE_ENABLED
28 |
29 | IS_GCM_ENABLED
30 |
31 | IS_SIGNIN_ENABLED
32 |
33 | GOOGLE_APP_ID
34 | 1:758773997881:ios:82656735bc074188d1c8e8
35 | DATABASE_URL
36 | https://fireship-lessons.firebaseio.com
37 |
38 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '10.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | - use_super_parameters
26 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
27 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
28 |
29 | # Additional information about this file can be found at
30 | # https://dart.dev/guides/language/analysis-options
31 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | quizapp
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_core/firebase_core.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:provider/provider.dart';
4 | import 'package:quizapp/routes.dart';
5 | import 'package:quizapp/services/services.dart';
6 | import 'package:quizapp/shared/shared.dart';
7 | import 'package:quizapp/theme.dart';
8 |
9 | void main() {
10 | WidgetsFlutterBinding.ensureInitialized();
11 | runApp(const App());
12 | }
13 |
14 | class App extends StatefulWidget {
15 | const App({super.key});
16 |
17 | @override
18 | State createState() => _AppState();
19 | }
20 |
21 | class _AppState extends State {
22 | final Future _initialization = Firebase.initializeApp();
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return FutureBuilder(
27 | // Initialize FlutterFire:
28 | future: _initialization,
29 | builder: (context, snapshot) {
30 | // Check for errors
31 | if (snapshot.hasError) {
32 | // Error screen
33 | }
34 |
35 | // Once complete, show your application
36 | if (snapshot.connectionState == ConnectionState.done) {
37 | return StreamProvider(
38 | create: (_) => FirestoreService().streamReport(),
39 | catchError: (_, err) => Report(),
40 | initialData: Report(),
41 | child: MaterialApp(
42 | debugShowCheckedModeBanner: true,
43 | routes: appRoutes,
44 | theme: appTheme),
45 | );
46 | }
47 |
48 | // Otherwise, show something whilst waiting for initialization to complete
49 | return const MaterialApp(home: LoadingScreen());
50 | },
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/services/firestore.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:cloud_firestore/cloud_firestore.dart';
3 | import 'package:rxdart/rxdart.dart';
4 | import 'package:quizapp/services/auth.dart';
5 | import 'package:quizapp/services/models.dart';
6 |
7 | class FirestoreService {
8 | final FirebaseFirestore _db = FirebaseFirestore.instance;
9 |
10 | /// Reads all documments from the topics collection
11 | Future> getTopics() async {
12 | var ref = _db.collection('topics');
13 | var snapshot = await ref.get();
14 | var data = snapshot.docs.map((s) => s.data());
15 | var topics = data.map((d) => Topic.fromJson(d));
16 | return topics.toList();
17 | }
18 |
19 | /// Retrieves a single quiz document
20 | Future getQuiz(String quizId) async {
21 | var ref = _db.collection('quizzes').doc(quizId);
22 | var snapshot = await ref.get();
23 | return Quiz.fromJson(snapshot.data() ?? {});
24 | }
25 |
26 | /// Listens to current user's report document in Firestore
27 | Stream streamReport() {
28 | return AuthService().userStream.switchMap((user) {
29 | if (user != null) {
30 | var ref = _db.collection('reports').doc(user.uid);
31 | return ref.snapshots().map((doc) => Report.fromJson(doc.data()!));
32 | } else {
33 | return Stream.fromIterable([Report()]);
34 | }
35 | });
36 | }
37 |
38 | /// Updates the current user's report document after completing quiz
39 | Future updateUserReport(Quiz quiz) {
40 | var user = AuthService().user!;
41 | var ref = _db.collection('reports').doc(user.uid);
42 |
43 | var data = {
44 | 'total': FieldValue.increment(1),
45 | 'topics': {
46 | quiz.topic: FieldValue.arrayUnion([quiz.id])
47 | }
48 | };
49 |
50 | return ref.set(data, SetOptions(merge: true));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/topics/topics.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
3 | import 'package:quizapp/services/services.dart';
4 | import 'package:quizapp/shared/shared.dart';
5 | import 'package:quizapp/topics/drawer.dart';
6 | import 'package:quizapp/topics/topic_item.dart';
7 |
8 | class TopicsScreen extends StatelessWidget {
9 | const TopicsScreen({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return FutureBuilder>(
14 | future: FirestoreService().getTopics(),
15 | builder: (context, snapshot) {
16 | if (snapshot.connectionState == ConnectionState.waiting) {
17 | return const LoadingScreen();
18 | } else if (snapshot.hasError) {
19 | return Center(
20 | child: ErrorMessage(message: snapshot.error.toString()),
21 | );
22 | } else if (snapshot.hasData) {
23 | var topics = snapshot.data!;
24 |
25 | return Scaffold(
26 | appBar: AppBar(
27 | backgroundColor: Colors.deepPurple,
28 | title: const Text('Topics'),
29 | actions: [
30 | IconButton(
31 | icon: Icon(
32 | FontAwesomeIcons.circleUser,
33 | color: Colors.pink[200],
34 | ),
35 | onPressed: () => Navigator.pushNamed(context, '/profile'),
36 | )
37 | ],
38 | ),
39 | drawer: TopicDrawer(topics: topics),
40 | body: GridView.count(
41 | primary: false,
42 | padding: const EdgeInsets.all(20.0),
43 | crossAxisSpacing: 10.0,
44 | crossAxisCount: 2,
45 | children: topics.map((topic) => TopicItem(topic: topic)).toList(),
46 | ),
47 | bottomNavigationBar: const BottomNavBar(),
48 | );
49 | } else {
50 | return const Text('No topics found in Firestore. Check database');
51 | }
52 | },
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/services/models.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 | part 'models.g.dart';
3 |
4 | @JsonSerializable()
5 | class Option {
6 | String value;
7 | String detail;
8 | bool correct;
9 | Option({this.value = '', this.detail = '', this.correct = false});
10 | factory Option.fromJson(Map json) => _$OptionFromJson(json);
11 | Map toJson() => _$OptionToJson(this);
12 | }
13 |
14 | @JsonSerializable()
15 | class Question {
16 | String text;
17 | List