├── 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
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── Podfile.lock
├── .gitignore
└── Podfile
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── manifest.json
└── index.html
├── assets
├── icons
│ ├── exam.png
│ ├── target.png
│ └── categories.png
├── flares
│ └── circle.flr
├── images
│ ├── failure.png
│ ├── topics
│ │ ├── cms.png
│ │ ├── sql.png
│ │ ├── devops.png
│ │ ├── docker.png
│ │ ├── github.png
│ │ ├── linux.png
│ │ └── coding-language.png
│ ├── gesture_suggestion.png
│ ├── gesture_show.svg
│ └── difficulty
│ │ └── any_difficulty.svg
└── fonts
│ ├── Poppins-Light.ttf
│ ├── Gotham Pro Bold.ttf
│ ├── Poppins-Regular.ttf
│ └── Gotham Pro Regular.ttf
├── dev_assets
└── logo.png
├── lib
├── config
│ ├── exceptions
│ │ ├── wrong_credential_exceptions.dart
│ │ └── server_exceptions.dart
│ ├── constants
│ │ ├── strings.dart
│ │ ├── palette.dart
│ │ ├── assets.dart
│ │ └── styles.dart
│ └── utils
│ │ ├── quiz_filter_controller.dart
│ │ └── correct_answer_definer.dart
├── presentation
│ ├── modal_bottom_sheets
│ │ ├── index.dart
│ │ └── new_habit_modal_bottom_sheet.dart
│ ├── dialogs
│ │ ├── index.dart
│ │ └── gesture_suggestion_dialog.dart
│ ├── widgets
│ │ ├── intro
│ │ │ ├── intro_image.dart
│ │ │ ├── intro_title.dart
│ │ │ └── intro_button.dart
│ │ ├── score
│ │ │ ├── score_title.dart
│ │ │ ├── correct_answer_checkbox_widget.dart
│ │ │ ├── circular_percent_show_indicator.dart
│ │ │ ├── score_desc.dart
│ │ │ ├── score_correct_answers_title.dart
│ │ │ └── correct_answers_builder.dart
│ │ ├── counter
│ │ │ ├── plasma_background.dart
│ │ │ ├── counter_value.dart
│ │ │ ├── counter_title.dart
│ │ │ └── animated_circles.dart
│ │ ├── buttons
│ │ │ ├── counter_next_button.dart
│ │ │ └── emphasized_button.dart
│ │ ├── quiz
│ │ │ ├── linear_percent_show_indicator.dart
│ │ │ ├── progress_bar.dart
│ │ │ ├── option.dart
│ │ │ └── question_card.dart
│ │ ├── home
│ │ │ ├── home_appbar.dart
│ │ │ ├── last_activity.dart
│ │ │ ├── percentage_bubble.dart
│ │ │ └── test_bubbles.dart
│ │ ├── difficulty
│ │ │ ├── difficulty_title.dart
│ │ │ └── difficulty_slider.dart
│ │ ├── splash
│ │ │ └── splash_animation.dart
│ │ └── index.dart
│ └── pages
│ │ ├── intro_page.dart
│ │ ├── index.dart
│ │ ├── splash_page.dart
│ │ ├── difficulty_page.dart
│ │ ├── quiz_page.dart
│ │ ├── home_page.dart
│ │ ├── score_page.dart
│ │ ├── counter_page.dart
│ │ ├── error_page.dart
│ │ └── topic_selection_page.dart
├── logic
│ └── cubit
│ │ ├── counter_state.dart
│ │ └── counter_cubit.dart
├── domain
│ ├── services
│ │ ├── navigation
│ │ │ ├── index.dart
│ │ │ ├── routes.dart
│ │ │ └── service.dart
│ │ └── get_it
│ │ │ ├── index.dart
│ │ │ └── service.dart
│ └── repositories
│ │ ├── score_store_repository.dart
│ │ ├── shared_preferences_store.dart
│ │ ├── server_repository.dart
│ │ └── quiz_repository.dart
├── data
│ ├── models
│ │ ├── view_model
│ │ │ ├── difficulty_model.dart
│ │ │ └── topic_selection_model.dart
│ │ └── response_model
│ │ │ └── quiz_response.dart
│ ├── helpers
│ │ └── dialog_helper.dart
│ └── utils
│ │ ├── difficulty.dart
│ │ └── topics.dart
├── app.dart
└── main.dart
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── launcher_icon.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── launcher_icon.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── launcher_icon.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── launcher_icon.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── launcher_icon.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── codequizzy_code_quizzy_app
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── build.gradle
├── .gitignore
└── settings.gradle
├── .metadata
├── .gitignore
├── README.md
├── LICENSE
├── pubspec.yaml
├── analysis_options.yaml
└── pubspec.lock
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/assets/icons/exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/icons/exam.png
--------------------------------------------------------------------------------
/dev_assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/dev_assets/logo.png
--------------------------------------------------------------------------------
/assets/icons/target.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/icons/target.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/assets/flares/circle.flr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/flares/circle.flr
--------------------------------------------------------------------------------
/assets/images/failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/failure.png
--------------------------------------------------------------------------------
/assets/icons/categories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/icons/categories.png
--------------------------------------------------------------------------------
/assets/images/topics/cms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/cms.png
--------------------------------------------------------------------------------
/assets/images/topics/sql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/sql.png
--------------------------------------------------------------------------------
/lib/config/exceptions/wrong_credential_exceptions.dart:
--------------------------------------------------------------------------------
1 | class AuthenticationException implements Exception {}
2 |
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/fonts/Poppins-Light.ttf
--------------------------------------------------------------------------------
/assets/images/topics/devops.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/devops.png
--------------------------------------------------------------------------------
/assets/images/topics/docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/docker.png
--------------------------------------------------------------------------------
/assets/images/topics/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/github.png
--------------------------------------------------------------------------------
/assets/images/topics/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/linux.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/assets/fonts/Gotham Pro Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/fonts/Gotham Pro Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/fonts/Poppins-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Gotham Pro Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/fonts/Gotham Pro Regular.ttf
--------------------------------------------------------------------------------
/assets/images/gesture_suggestion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/gesture_suggestion.png
--------------------------------------------------------------------------------
/assets/images/topics/coding-language.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/assets/images/topics/coding-language.png
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=--add-opens java.base/java.io=ALL-UNNAMED
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-hdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/config/exceptions/server_exceptions.dart:
--------------------------------------------------------------------------------
1 | abstract class ServerExceptions {
2 | static const authenticationException = 'error: "Unauthenticated"';
3 | }
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/lib/presentation/modal_bottom_sheets/index.dart:
--------------------------------------------------------------------------------
1 | library modal_bottom_sheets;
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | part 'new_habit_modal_bottom_sheet.dart';
6 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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/iamnijat/code-quizzy/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/lib/logic/cubit/counter_state.dart:
--------------------------------------------------------------------------------
1 | part of 'counter_cubit.dart';
2 |
3 | class CounterState {
4 | final int counterValue;
5 | CounterState({required this.counterValue});
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamnijat/code-quizzy/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/iamnijat/code-quizzy/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 |
--------------------------------------------------------------------------------
/lib/domain/services/navigation/index.dart:
--------------------------------------------------------------------------------
1 | library navigation;
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:quiz_programming/presentation/pages/index.dart';
5 | part 'routes.dart';
6 | part 'service.dart';
7 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/codequizzy_code_quizzy_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.codequizzy_code_quizzy_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
6 |
--------------------------------------------------------------------------------
/lib/data/models/view_model/difficulty_model.dart:
--------------------------------------------------------------------------------
1 | class DifficultyModel {
2 | final String? slideImgUrl;
3 | final String? slideTitle;
4 |
5 | DifficultyModel({
6 | required this.slideImgUrl,
7 | required this.slideTitle,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/data/models/view_model/topic_selection_model.dart:
--------------------------------------------------------------------------------
1 | class TopicSelectionModel {
2 | final String? title;
3 | final String? imgUrl;
4 | bool isSelected;
5 |
6 | TopicSelectionModel({
7 | required this.title,
8 | required this.imgUrl,
9 | this.isSelected = false,
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 |
13 | tasks.register("clean", Delete) {
14 | delete rootProject.buildDir
15 | }
16 |
--------------------------------------------------------------------------------
/.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: 77d935af4db863f6abd0b9c31c7e6df2a13de57b
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/data/helpers/dialog_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import '../../presentation/dialogs/index.dart';
3 |
4 | Future showGestureSuggestionDialog(
5 | context,
6 | ) {
7 | return showDialog(
8 | context: context,
9 | barrierDismissible: true,
10 | builder: (BuildContext context) => const GestureSuggestionDialog(),
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/config/constants/strings.dart:
--------------------------------------------------------------------------------
1 | abstract class AppStrings {
2 | //Server Repo
3 | static const apiKey = 'MrSORkLFSsJabARtQhyloo7574YX2dquEAchMn8x';
4 | static const apiHost = 'https://quizapi.io/api/v1/questions?apiKey=$apiKey';
5 | //Shared Prefrences
6 | static const lastQuizScore = 'last_quiz_score';
7 | static const scoreCredentials = "score_credentials";
8 | static const firstSeen = "first_seen";
9 | }
10 |
--------------------------------------------------------------------------------
/lib/presentation/dialogs/index.dart:
--------------------------------------------------------------------------------
1 | library dialogs;
2 |
3 | import 'package:animated_text_kit/animated_text_kit.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:quiz_programming/config/constants/assets.dart';
6 | import 'package:quiz_programming/config/constants/palette.dart';
7 | import 'package:quiz_programming/config/constants/styles.dart';
8 | import 'package:sizer/sizer.dart';
9 | part 'gesture_suggestion_dialog.dart';
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/intro/intro_image.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class IntroImage extends StatelessWidget {
4 | const IntroImage({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Container(
9 | height: 50.h,
10 | width: 100.w,
11 | alignment: Alignment.center,
12 | color: AppPalette.transparentColor,
13 | child: SvgPicture.asset(AppImages.homeImage));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/score_title.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class ScoreTitle extends StatelessWidget {
4 | const ScoreTitle({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Row(
9 | mainAxisAlignment: MainAxisAlignment.start,
10 | children: [
11 | Text(
12 | "Points",
13 | style: AppStyles.scoreTitleTextStyle,
14 | ),
15 | ],
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/counter/plasma_background.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class PlasmaBackground extends StatelessWidget {
4 | const PlasmaBackground({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Container(
11 | height: 50.h,
12 | decoration: const BoxDecoration(
13 | color: AppPalette.whiteColor,
14 | backgroundBlendMode: BlendMode.srcOver,
15 | ),
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/presentation/modal_bottom_sheets/new_habit_modal_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | part of modal_bottom_sheets;
2 |
3 | class NewHabitModalBottomSheet extends StatelessWidget {
4 | const NewHabitModalBottomSheet({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return const SingleChildScrollView(
11 | child: Material(
12 | type: MaterialType.transparency,
13 | child: Column(children: []),
14 | ));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/presentation/pages/intro_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class IntroPage extends StatelessWidget {
4 | const IntroPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const Scaffold(
9 | backgroundColor: AppPalette.whiteColor,
10 | body: Column(
11 | children: [
12 | IntroImage(),
13 | IntroTitle(),
14 | IntroButton(),
15 | ],
16 | ),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/intro/intro_title.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class IntroTitle extends StatelessWidget {
4 | const IntroTitle({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Padding(
9 | padding: EdgeInsets.symmetric(horizontal: 5.h),
10 | child: Text(
11 | "Are you ready to learn programming easily in the funniest way?",
12 | style: AppStyles.homeTitleTextStyle,
13 | ),
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/counter/counter_value.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CounterValue extends StatelessWidget {
4 | const CounterValue({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | String? counterValue = context
11 | .select((CounterCubit counterCubit) => counterCubit.state.counterValue)
12 | .toString();
13 | return Text(
14 | counterValue,
15 | style: TextStyle(
16 | fontWeight: FontWeight.bold, fontSize: 36.9.sp, color: Colors.white),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/domain/services/get_it/index.dart:
--------------------------------------------------------------------------------
1 | library get_it;
2 |
3 | import 'package:get_it/get_it.dart';
4 | import 'package:quiz_programming/domain/repositories/quiz_repository.dart';
5 | import 'package:quiz_programming/domain/repositories/score_store_repository.dart';
6 | import 'package:quiz_programming/domain/repositories/server_repository.dart';
7 | import 'package:quiz_programming/domain/repositories/shared_preferences_store.dart';
8 | import 'package:quiz_programming/domain/services/navigation/index.dart';
9 | import 'package:quiz_programming/logic/cubit/counter_cubit.dart';
10 | part 'service.dart';
11 |
--------------------------------------------------------------------------------
/lib/logic/cubit/counter_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | part 'counter_state.dart';
3 |
4 | class CounterCubit extends Cubit {
5 | final maxInt = 9;
6 | final minInt = 4;
7 | CounterCubit() : super(CounterState(counterValue: 5));
8 |
9 | void increment() => emit(CounterState(
10 | counterValue: state.counterValue <= maxInt
11 | ? state.counterValue + 1
12 | : state.counterValue));
13 | void decrement() => emit(CounterState(
14 | counterValue: state.counterValue >= minInt
15 | ? state.counterValue - 1
16 | : state.counterValue));
17 | }
18 |
--------------------------------------------------------------------------------
/lib/domain/services/get_it/service.dart:
--------------------------------------------------------------------------------
1 | part of get_it;
2 |
3 | void setupLocator(GetIt getIt) {
4 | //Providers
5 | getIt.registerLazySingleton(() => const NavigationService());
6 | getIt.registerLazySingleton(() => ServerRepository());
7 | getIt.registerLazySingleton(() => SharedPreferencesStore());
8 | getIt.registerLazySingleton(
9 | () => ScoreStoreRepository(GetIt.I.get()));
10 | //ChangeNotifierProviders
11 | getIt.registerLazySingleton(
12 | () => QuizRepository(GetIt.I.get()));
13 | //Cubits
14 | getIt.registerLazySingleton(() => CounterCubit());
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - shared_preferences_ios (0.0.1):
4 | - Flutter
5 |
6 | DEPENDENCIES:
7 | - Flutter (from `Flutter`)
8 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
9 |
10 | EXTERNAL SOURCES:
11 | Flutter:
12 | :path: Flutter
13 | shared_preferences_ios:
14 | :path: ".symlinks/plugins/shared_preferences_ios/ios"
15 |
16 | SPEC CHECKSUMS:
17 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
18 | shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32
19 |
20 | PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
21 |
22 | COCOAPODS: 1.11.3
23 |
--------------------------------------------------------------------------------
/lib/data/utils/difficulty.dart:
--------------------------------------------------------------------------------
1 | import '../../config/constants/assets.dart';
2 | import '../models/view_model/difficulty_model.dart';
3 |
4 | class Difficulty {
5 | static List getDifficultyList() {
6 | return [
7 | DifficultyModel(
8 | slideTitle: "EASY",
9 | slideImgUrl: AppImages.easy,
10 | ),
11 | DifficultyModel(slideTitle: "MEDIUM", slideImgUrl: AppImages.medium),
12 | DifficultyModel(
13 | slideTitle: "DIFFICULT", slideImgUrl: AppImages.difficult),
14 | DifficultyModel(
15 | slideTitle: "ANY DIFFICULTY", slideImgUrl: AppImages.anyDifficulty),
16 | ];
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/config/utils/quiz_filter_controller.dart:
--------------------------------------------------------------------------------
1 | class QuizFilterController {
2 | static String? getParams({
3 | required String filter,
4 | required String? category,
5 | required String? difficulty,
6 | required String? limit,
7 | }) {
8 | String? newParams;
9 | //Students Section
10 | if (filter == 'normal_quiz') {
11 | newParams = '&category=$category&difficulty=$difficulty&limit=$limit';
12 | }
13 | if (filter == 'random_quiz') {
14 | newParams = '&limit=10';
15 | }
16 | if (filter == 'category_quiz') {
17 | newParams = '&category=$category&limit=10';
18 | }
19 |
20 | return newParams;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:sizer/sizer.dart';
3 | import 'domain/services/navigation/index.dart';
4 |
5 | class MyApp extends StatelessWidget {
6 | const MyApp({Key? key}) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Sizer(builder: (context, orientation, deviceType) {
11 | return MaterialApp(
12 | navigatorKey: NavigationService.navigationKey,
13 | debugShowCheckedModeBanner: false,
14 | title: 'Programming Quiz',
15 | initialRoute: NavigationRoutes.splash,
16 | onGenerateRoute: generateRoute,
17 | );
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/correct_answer_checkbox_widget.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CorrectAnswerCheckboxWidget extends StatelessWidget {
4 | const CorrectAnswerCheckboxWidget({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Positioned(
11 | right: -3.w,
12 | top: -3.w,
13 | child: Container(
14 | height: 4.h,
15 | width: 4.h,
16 | decoration: AppStyles.mainBoxDecorationStyle,
17 | child: Icon(
18 | Icons.done,
19 | size: 3.h,
20 | color: AppPalette.whiteColor,
21 | ),
22 | ));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/buttons/counter_next_button.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CounterNextButton extends StatelessWidget {
4 | final VoidCallback nextPress;
5 | const CounterNextButton({Key? key, required this.nextPress})
6 | : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Row(
11 | mainAxisAlignment: MainAxisAlignment.end,
12 | children: [
13 | TextButton(
14 | onPressed: () {
15 | nextPress();
16 | },
17 | child: Text(
18 | "Next",
19 | style: AppStyles.counterNextButtonStyle,
20 | ))
21 | ],
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/circular_percent_show_indicator.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CircularPercentShowIndicator extends StatelessWidget {
4 | final double percent;
5 |
6 | const CircularPercentShowIndicator({Key? key, required this.percent})
7 | : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return CircularPercentIndicator(
12 | radius: 9.h,
13 | lineWidth: 23.0,
14 | animation: true,
15 | animationDuration: 1500,
16 | percent: percent,
17 | backgroundColor: AppPalette.progressBarColor,
18 | circularStrokeCap: CircularStrokeCap.round,
19 | progressColor: AppPalette.homeButtonColor,
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/quiz/linear_percent_show_indicator.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class LinearPercentShowIndicator extends StatelessWidget {
4 | const LinearPercentShowIndicator({
5 | Key? key,
6 | required this.index,
7 | required this.length,
8 | }) : super(key: key);
9 |
10 | final int index;
11 | final int length;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return LinearPercentIndicator(
16 | backgroundColor: AppPalette.progressBarColor,
17 | width: 75.w,
18 | animation: true,
19 | lineHeight: 2.5.h,
20 | animationDuration: 800,
21 | percent: index / length,
22 | barRadius: const Radius.circular(15),
23 | progressColor: AppPalette.homeButtonColor);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/counter/counter_title.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CounterTitle extends StatelessWidget {
4 | const CounterTitle({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Padding(
9 | padding: AppStyles.mainPaddingStyle,
10 | child: RichText(
11 | textAlign: TextAlign.center,
12 | text: TextSpan(children: [
13 | TextSpan(
14 | text: "How many questions do you want to answer?\n",
15 | style: AppStyles.counterTitleTextStyle,
16 | ),
17 | TextSpan(
18 | text: "Choose a number between 1 and 10",
19 | style: AppStyles.counterDescTextStyle,
20 | ),
21 | ]),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/score_desc.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class ScoreDesc extends StatelessWidget {
4 | final double percentage;
5 |
6 | const ScoreDesc({Key? key, required this.percentage}) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Flexible(
11 | child: RichText(
12 | textAlign: TextAlign.center,
13 | text: TextSpan(children: [
14 | TextSpan(
15 | text: "Mission Completed\n",
16 | style: AppStyles.scorePercentageTitleStyle,
17 | ),
18 | TextSpan(
19 | text: "${(percentage * 100).toStringAsFixed(2)}%",
20 | style: AppStyles.scorePercentageDescTextStyle,
21 | ),
22 | ]),
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/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 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version "8.6.0" apply false
23 | id "org.jetbrains.kotlin.android" version "2.0.20" apply false
24 | }
25 |
26 | include ':app'
27 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/home/home_appbar.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class HomeAppbar extends StatelessWidget {
4 | const HomeAppbar({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Padding(
11 | padding: AppStyles.secondaryPaddingStyle,
12 | child: Row(
13 | mainAxisAlignment: MainAxisAlignment.start,
14 | children: [
15 | Container(
16 | height: 15.h,
17 | width: 20.w,
18 | alignment: Alignment.center,
19 | color: AppPalette.transparentColor,
20 | child: SvgPicture.asset(AppImages.coderIcon)),
21 | SizedBox(
22 | width: 5.w,
23 | ),
24 | Text(
25 | "Hello, Coder",
26 | style: AppStyles.quizQuestionTextStyle,
27 | ),
28 | ],
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.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 | **/android/key.properties
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Android Studio will place build artifacts here
45 | /android/app/debug
46 | /android/app/profile
47 | /android/app/release
48 |
--------------------------------------------------------------------------------
/lib/domain/repositories/score_store_repository.dart:
--------------------------------------------------------------------------------
1 | import 'shared_preferences_store.dart';
2 |
3 | class ScoreStoreRepository {
4 | final SharedPreferencesStore _sharedPreferencesStore;
5 | const ScoreStoreRepository(this._sharedPreferencesStore);
6 |
7 | Future get quizLastScore =>
8 | _sharedPreferencesStore.getQuizLastScore();
9 |
10 | Future?> get scoreCredentials =>
11 | _sharedPreferencesStore.getScoreCredentials();
12 |
13 | Future get imgUrl async =>
14 | (await _sharedPreferencesStore.getScoreCredentials())[0];
15 | Future get category async =>
16 | (await _sharedPreferencesStore.getScoreCredentials())[1];
17 | void setQuizScore(value) {
18 | _sharedPreferencesStore.setQuizLastScore(value);
19 | }
20 |
21 | void setScoreCredentials({required String imgUrl, required String category}) {
22 | _sharedPreferencesStore.setScoreCredentials(
23 | score: imgUrl, category: category);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/difficulty/difficulty_title.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class DifficultyTitle extends StatelessWidget {
4 | const DifficultyTitle({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Padding(
9 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 10.h),
10 | child: Column(
11 | crossAxisAlignment: CrossAxisAlignment.center,
12 | children: [
13 | Text(
14 | "Please, select the difficulty level to play in this game",
15 | style: AppStyles.counterTitleTextStyle,
16 | textAlign: TextAlign.center,
17 | ),
18 | SizedBox(
19 | height: 1.5.h,
20 | ),
21 | Text(
22 | "Please, slide to choose the difficulty level",
23 | style: AppStyles.difficultyDescStyle,
24 | textAlign: TextAlign.center,
25 | )
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/score_correct_answers_title.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class ScoreCorrectAnswersTitle extends StatelessWidget {
4 | const ScoreCorrectAnswersTitle({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Padding(
11 | padding: AppStyles.mainPaddingStyle,
12 | child: Row(
13 | mainAxisAlignment: MainAxisAlignment.start,
14 | children: [
15 | Container(
16 | height: 5.5.h,
17 | width: 5.5.h,
18 | decoration: AppStyles.mainBoxDecorationStyle,
19 | child: const Icon(
20 | Icons.code_rounded,
21 | color: AppPalette.whiteColor,
22 | )),
23 | SizedBox(
24 | width: 2.h,
25 | ),
26 | Text(
27 | "Correct Answers",
28 | style: AppStyles.scoreWrongAnswersTitleStyle,
29 | )
30 | ],
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/quiz/progress_bar.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class ProgressBar extends StatelessWidget {
4 | final int index;
5 | final int length;
6 |
7 | const ProgressBar({Key? key, required this.index, required this.length})
8 | : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Padding(
13 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 8.h),
14 | child: Row(
15 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
16 | children: [
17 | LinearPercentShowIndicator(index: index, length: length),
18 | RichText(
19 | text: TextSpan(children: [
20 | TextSpan(
21 | text: "$index/",
22 | style: AppStyles.quizProgressBarIndexStyle,
23 | ),
24 | TextSpan(
25 | text: "$length",
26 | style: AppStyles.quizProgressBarLengthStyle,
27 | ),
28 | ]),
29 | ),
30 | ],
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "quiz_programming",
3 | "short_name": "quiz_programming",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/lib/config/utils/correct_answer_definer.dart:
--------------------------------------------------------------------------------
1 | import '../../data/models/response_model/quiz_response.dart';
2 |
3 | class CorrectAnswerDefiner {
4 | static String? getCorrectAnswer(
5 | {required int index, required List? questionsList}) {
6 | String? correctAns;
7 | var correctAnswerList = questionsList?[index]!.correctAnswers;
8 | var answers = questionsList?[index]!.answers;
9 | if (correctAnswerList!.answerACorrect == "true") {
10 | correctAns = answers!.answerA!;
11 | }
12 | if (correctAnswerList.answerBCorrect == "true") {
13 | correctAns = answers!.answerB!;
14 | }
15 | if (correctAnswerList.answerCCorrect == "true") {
16 | correctAns = answers!.answerC!;
17 | }
18 | if (correctAnswerList.answerDCorrect == "true") {
19 | correctAns = answers!.answerD!;
20 | }
21 | if (correctAnswerList.answerECorrect == "true") {
22 | correctAns = answers!.answerE!;
23 | }
24 | if (correctAnswerList.answerFCorrect == "true") {
25 | correctAns = answers!.answerF!;
26 | }
27 |
28 | return correctAns;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 
6 | 
7 | 
8 |
9 | # Flutter Code Quizzy Application
10 |
11 |
12 | 
13 |
14 |
15 | -------
16 |
17 | ## Configuration for this application
18 |
19 | Fortunately, there is no configuration for this project apart from the flutter development setup on your computer.
20 |
21 | You've done entire steps correctly and I make sure that this project will have paramount effect on your progress learning `Flutter`
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Nijat Namazzade
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/buttons/emphasized_button.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class EmphasizedButton extends StatelessWidget {
4 | final String title;
5 | final VoidCallback onButtonTap;
6 |
7 | const EmphasizedButton(
8 | {Key? key, required this.title, required this.onButtonTap})
9 | : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Container(
14 | width: 100.w,
15 | height: deviceTablet ? 9.h : 8.h,
16 | margin: EdgeInsets.only(top: 4.h),
17 | alignment: Alignment.bottomCenter,
18 | decoration: BoxDecoration(
19 | borderRadius: BorderRadius.circular(10),
20 | color: AppPalette.homeButtonColor,
21 | ),
22 | child: Material(
23 | color: AppPalette.transparentColor,
24 | child: InkWell(
25 | onTap: onButtonTap,
26 | child: Center(
27 | child: Text(
28 | title,
29 | textAlign: TextAlign.center,
30 | style: AppStyles.difficultyButtonStyle,
31 | ),
32 | )),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/config/constants/palette.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class AppPalette {
4 | static const whiteColor = Colors.white;
5 | static const blackColor = Colors.black;
6 | static const greyColor = Colors.grey;
7 | static const blueGrey = Colors.blueGrey;
8 | static const greenColor = Colors.greenAccent;
9 | static const transparentColor = Colors.transparent;
10 | static const homeHeadlineColor = Color.fromRGBO(78, 95, 130, 1);
11 | static const homeButtonColor = Color.fromRGBO(86, 102, 238, 1);
12 | static const headlineSecondColor = Color.fromRGBO(28, 133, 232, 1);
13 | static const headlineThirdColor = Color.fromRGBO(254, 187, 148, 1);
14 | static const selectedContainerColor = Color.fromRGBO(129, 132, 227, 1);
15 | static const headlineFourthColor = Color.fromRGBO(0, 60, 61, 1);
16 | static const progressBarColor = Color.fromRGBO(240, 251, 255, 1);
17 | static const errorColor = Color.fromRGBO(235, 87, 87, 1);
18 | static const homeContainerColor = Color.fromRGBO(255, 246, 236, 1);
19 | static const homeCategoryBackColor = Color.fromRGBO(210, 255, 208, 1);
20 | static const homeRandomTestBackColor = Color.fromRGBO(254, 233, 238, 1);
21 | static const homeTakeTestBackColor = Color.fromRGBO(241, 233, 252, 1);
22 | }
23 |
--------------------------------------------------------------------------------
/lib/data/utils/topics.dart:
--------------------------------------------------------------------------------
1 | import '../../config/constants/assets.dart';
2 | import '../models/view_model/topic_selection_model.dart';
3 |
4 | class Topics {
5 | static List getAllTopics() {
6 | return [
7 | TopicSelectionModel(
8 | title: "Linux",
9 | imgUrl: AppImages.linuxPicture,
10 | isSelected: true,
11 | ),
12 | TopicSelectionModel(
13 | title: "Bash",
14 | imgUrl: AppImages.githubPicture,
15 | isSelected: false,
16 | ),
17 | TopicSelectionModel(
18 | title: "Docker",
19 | imgUrl: AppImages.dockerPicture,
20 | isSelected: false,
21 | ),
22 | TopicSelectionModel(
23 | title: "SQL",
24 | imgUrl: AppImages.sqlPicture,
25 | isSelected: false,
26 | ),
27 | TopicSelectionModel(
28 | title: "CMS",
29 | imgUrl: AppImages.cmsPicture,
30 | isSelected: false,
31 | ),
32 | TopicSelectionModel(
33 | title: "Code",
34 | imgUrl: AppImages.codingPicture,
35 | isSelected: false,
36 | ),
37 | TopicSelectionModel(
38 | title: "DevOps",
39 | imgUrl: AppImages.devopsPicture,
40 | isSelected: false,
41 | ),
42 | ];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/config/constants/assets.dart:
--------------------------------------------------------------------------------
1 | abstract class AppImages {
2 | static const homeImage = 'assets/images/home_image.svg';
3 | static const splashImage = 'assets/images/splash_image.svg';
4 | static const counterFlare = 'assets/flares/circle.flr';
5 | static const gestureSuggestion = 'assets/images/gesture_suggestion.png';
6 | static const cmsPicture = 'assets/images/topics/cms.png';
7 | static const codingPicture = 'assets/images/topics/coding-language.png';
8 | static const devopsPicture = 'assets/images/topics/devops.png';
9 | static const githubPicture = 'assets/images/topics/github.png';
10 | static const linuxPicture = 'assets/images/topics/linux.png';
11 | static const sqlPicture = 'assets/images/topics/sql.png';
12 | static const dockerPicture = 'assets/images/topics/docker.png';
13 | static const easy = 'assets/images/difficulty/easy.svg';
14 | static const medium = 'assets/images/difficulty/medium.svg';
15 | static const difficult = 'assets/images/difficulty/difficult.svg';
16 | static const anyDifficulty = 'assets/images/difficulty/any_difficulty.svg';
17 | static const coderIcon = 'assets/icons/coder_icon.svg';
18 | static const categoryImage = 'assets/icons/categories.png';
19 | static const randomTestImage = 'assets/icons/target.png';
20 | static const takeTestImage = 'assets/icons/exam.png';
21 | static const failureImage = 'assets/images/failure.png';
22 | }
23 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: quiz_programming
2 | description: A new Flutter project.
3 |
4 | publish_to: "none"
5 |
6 | version: 1.0.1+6
7 |
8 | environment:
9 | sdk: ">=2.15.1 <3.0.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | cupertino_icons: ^1.0.2
15 | sizer: ^2.0.15
16 | provider: ^6.0.2
17 | flutter_bloc: ^8.0.1
18 | get_it: ^7.2.0
19 | shared_preferences: ^2.0.12
20 | http: ^0.13.4
21 | flutter_svg: ^1.0.1
22 | animate_do: ^2.1.0
23 | swipe: ^0.0.1
24 | animated_text_kit: ^4.2.1
25 | percent_indicator: ^4.0.0
26 | dev_dependencies:
27 | flutter_launcher_icons: ^0.9.2
28 | flutter_lints: ^1.0.4
29 | flutter_test:
30 | sdk: flutter
31 | flutter_icons:
32 | android: "launcher_icon"
33 | image_path: "dev_assets/logo.png"
34 | flutter_lints: ^1.0.0
35 |
36 | flutter:
37 | uses-material-design: true
38 | assets:
39 | - assets/images/
40 | - assets/images/topics/
41 | - assets/images/difficulty/
42 | - assets/icons/
43 | - assets/flares/
44 |
45 | fonts:
46 | - family: Poppins
47 | fonts:
48 | - asset: assets/fonts/Poppins-Light.ttf
49 | - asset: assets/fonts/Poppins-Regular.ttf
50 | - family: Gotham Pro
51 | fonts:
52 | - asset: assets/fonts/Gotham Pro Regular.ttf
53 | - family: Gotham Pro Bold
54 | fonts:
55 | - asset: assets/fonts/Gotham Pro Bold.ttf
56 |
--------------------------------------------------------------------------------
/lib/domain/repositories/shared_preferences_store.dart:
--------------------------------------------------------------------------------
1 | import '../../config/constants/strings.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 |
4 | class SharedPreferencesStore {
5 | SharedPreferences? _sp;
6 |
7 | Future _init() async {
8 | _sp = await SharedPreferences.getInstance();
9 | return _sp;
10 | }
11 |
12 | Future getQuizLastScore() async {
13 | var sp = await _init();
14 | return sp?.getDouble(AppStrings.lastQuizScore);
15 | }
16 |
17 | Future setQuizLastScore(value) async {
18 | final sp = await _init();
19 | await sp?.setDouble(AppStrings.lastQuizScore, value);
20 | }
21 |
22 | Future setScoreCredentials({
23 | required String score,
24 | required String category,
25 | }) async {
26 | final sp = await _init();
27 | await sp?.setStringList(AppStrings.scoreCredentials, [
28 | score,
29 | category,
30 | ]);
31 | }
32 |
33 | Future> getScoreCredentials() async {
34 | final sp = await _init();
35 | return sp?.getStringList(AppStrings.scoreCredentials) ?? [];
36 | }
37 |
38 | Future getFirstSeen() async {
39 | var sp = await _init();
40 | return sp?.getBool(AppStrings.firstSeen);
41 | }
42 |
43 | Future setFirstSeen() async {
44 | final sp = await _init();
45 | await sp?.setBool(AppStrings.firstSeen, true);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/presentation/pages/index.dart:
--------------------------------------------------------------------------------
1 | library pages;
2 |
3 | import 'dart:async';
4 |
5 | import 'package:animate_do/animate_do.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:provider/provider.dart';
8 | import 'package:quiz_programming/config/constants/assets.dart';
9 | import 'package:quiz_programming/config/constants/palette.dart';
10 | import 'package:quiz_programming/config/constants/styles.dart';
11 | import 'package:quiz_programming/data/helpers/dialog_helper.dart';
12 | import 'package:quiz_programming/data/models/view_model/topic_selection_model.dart';
13 | import 'package:quiz_programming/data/utils/topics.dart';
14 | import 'package:quiz_programming/domain/repositories/quiz_repository.dart';
15 | import 'package:quiz_programming/domain/repositories/score_store_repository.dart';
16 | import 'package:quiz_programming/domain/repositories/shared_preferences_store.dart';
17 | import 'package:quiz_programming/domain/services/navigation/index.dart';
18 | import 'package:quiz_programming/logic/cubit/counter_cubit.dart';
19 | import 'package:quiz_programming/presentation/widgets/index.dart';
20 | import 'package:sizer/sizer.dart';
21 | import 'package:swipe/swipe.dart';
22 | part 'quiz_page.dart';
23 | part 'intro_page.dart';
24 | part 'splash_page.dart';
25 | part 'counter_page.dart';
26 | part 'topic_selection_page.dart';
27 | part 'difficulty_page.dart';
28 | part 'score_page.dart';
29 | part 'home_page.dart';
30 | part 'error_page.dart';
31 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '12.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 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/intro/intro_button.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class IntroButton extends StatefulWidget {
4 | const IntroButton({Key? key}) : super(key: key);
5 |
6 | @override
7 | _IntroButtonState createState() => _IntroButtonState();
8 | }
9 |
10 | class _IntroButtonState extends State {
11 | @override
12 | Widget build(BuildContext context) {
13 | return Expanded(
14 | child: Align(
15 | alignment: FractionalOffset.bottomCenter,
16 | child: Container(
17 | width: 70.w,
18 | height: deviceTablet ? 9.h : 8.h,
19 | margin: EdgeInsets.only(bottom: 6.h),
20 | alignment: Alignment.bottomCenter,
21 | decoration: BoxDecoration(
22 | borderRadius: BorderRadius.circular(50),
23 | color: AppPalette.homeButtonColor,
24 | ),
25 | child: Material(
26 | color: AppPalette.transparentColor,
27 | child: InkWell(
28 | onTap: _openNumberOfQuestionsPage,
29 | child: Center(
30 | child: Text(
31 | "Start now",
32 | textAlign: TextAlign.center,
33 | style: AppStyles.homeButtonTextStyle,
34 | ),
35 | )),
36 | ),
37 | ),
38 | ),
39 | );
40 | }
41 |
42 | void _openNumberOfQuestionsPage() {
43 | Provider.of(context, listen: false)
44 | .openSelectNumberOfQuestionsPage(context, withReplacement: false);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/domain/services/navigation/routes.dart:
--------------------------------------------------------------------------------
1 | part of navigation;
2 |
3 | class NavigationRoutes {
4 | static const String splash = '/';
5 | static const String home = '/home';
6 | static const String intro = '/intro';
7 | static const String counter = '/counter';
8 | static const String topicSelection = '/topicSelection';
9 | static const String difficulty = '/difficulty';
10 | static const String quizPage = '/quizpage';
11 | static const String scorePage = '/scorepage';
12 | static const String errorPage = '/errorpage';
13 | }
14 |
15 | Route generateRoute(RouteSettings settings) {
16 | switch (settings.name) {
17 | case NavigationRoutes.splash:
18 | return MaterialPageRoute(builder: (_) => const SplashPage());
19 | case NavigationRoutes.intro:
20 | return MaterialPageRoute(builder: (_) => const IntroPage());
21 | case NavigationRoutes.home:
22 | return MaterialPageRoute(builder: (_) => const HomePage());
23 | case NavigationRoutes.counter:
24 | return MaterialPageRoute(builder: (_) => const CounterPage());
25 | case NavigationRoutes.topicSelection:
26 | return MaterialPageRoute(builder: (_) => const TopicSelectionPage());
27 | case NavigationRoutes.difficulty:
28 | return MaterialPageRoute(builder: (_) => const DifficultyPage());
29 | case NavigationRoutes.quizPage:
30 | return MaterialPageRoute(builder: (_) => const QuizPage());
31 | case NavigationRoutes.scorePage:
32 | return MaterialPageRoute(builder: (_) => const ScorePage());
33 | case NavigationRoutes.errorPage:
34 | return MaterialPageRoute(builder: (_) => const ErrorPage());
35 | default:
36 | throw 'Invalid route';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/presentation/pages/splash_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class SplashPage extends StatefulWidget {
4 | const SplashPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _SplashPageState();
8 | }
9 |
10 | class _SplashPageState extends State {
11 | @override
12 | void initState() {
13 | super.initState();
14 | _checkFirstPage();
15 | }
16 |
17 | Future _checkFirstPage() async {
18 | var _provider = Provider.of(context, listen: false);
19 | _provider.getScoreCredentials(context);
20 | final _lastScore =
21 | await Provider.of(context, listen: false)
22 | .quizLastScore;
23 | _provider.getLastQuizScore(context);
24 |
25 | if (_lastScore == null) {
26 | Timer(const Duration(seconds: 4), _openIntroPage);
27 | } else {
28 | Timer(const Duration(seconds: 4), _openHomePage);
29 | }
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | return const Scaffold(
35 | backgroundColor: AppPalette.whiteColor,
36 | body: Column(
37 | mainAxisAlignment: MainAxisAlignment.center,
38 | crossAxisAlignment: CrossAxisAlignment.center,
39 | children: [
40 | SplashAnimation(),
41 | ],
42 | ),
43 | );
44 | }
45 |
46 | void _openIntroPage() {
47 | Provider.of(context, listen: false)
48 | .openIntroPage(context, withReplacement: true);
49 | }
50 |
51 | void _openHomePage() {
52 | Provider.of(context, listen: false)
53 | .openHomePage(context, withReplacement: true);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/home/last_activity.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class LastActivity extends StatelessWidget {
4 | const LastActivity({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Consumer(
9 | builder: (context, quiz, widget) => Padding(
10 | padding: AppStyles.mainPaddingStyle,
11 | child: Row(
12 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
13 | children: [
14 | Row(
15 | mainAxisAlignment: MainAxisAlignment.start,
16 | children: [
17 | Container(
18 | height: 10.h,
19 | width: 11.w,
20 | alignment: Alignment.center,
21 | color: AppPalette.transparentColor,
22 | child: Image.asset(quiz.topicImage.toString()),
23 | ),
24 | SizedBox(
25 | width: 4.w,
26 | ),
27 | Text(
28 | quiz.topic.toString(),
29 | style: AppStyles.lastActivityHomeTopicTextStyle,
30 | )
31 | ],
32 | ),
33 | Row(
34 | children: [
35 | const Icon(Icons.text_rotation_angledown,
36 | color: AppPalette.greenColor),
37 | SizedBox(
38 | width: 2.w,
39 | ),
40 | Text(
41 | quiz.score!.toStringAsFixed(0) + "%",
42 | style: AppStyles.lastActivityHomeScoreTextStyle,
43 | ),
44 | ],
45 | ),
46 | ],
47 | ),
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/splash/splash_animation.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class SplashAnimation extends StatefulWidget {
4 | const SplashAnimation({Key? key}) : super(key: key);
5 |
6 | @override
7 | _SplashAnimationState createState() => _SplashAnimationState();
8 | }
9 |
10 | class _SplashAnimationState extends State
11 | with SingleTickerProviderStateMixin {
12 | AnimationController? animationController;
13 | late Animation? animation;
14 |
15 | @override
16 | void initState() {
17 | super.initState();
18 | _rotateImage();
19 | }
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Transform.rotate(
24 | angle: animation!.value,
25 | child: Container(
26 | height: 60.h,
27 | width: 100.w,
28 | alignment: Alignment.center,
29 | color: AppPalette.transparentColor,
30 | child: SvgPicture.asset(AppImages.splashImage)),
31 | );
32 | }
33 |
34 | void _rotateImage() {
35 | animationController =
36 | AnimationController(duration: const Duration(seconds: 4), vsync: this);
37 | animation = Tween(begin: 0, end: 2 * math.pi)
38 | .chain(CurveTween(curve: Curves.bounceIn))
39 | .animate(animationController!)
40 | ..addListener(() {
41 | setState(() {});
42 | })
43 | ..addStatusListener((status) {
44 | if (status == AnimationStatus.completed) {
45 | animationController?.reverse();
46 | } else if (status == AnimationStatus.dismissed) {
47 | animationController?.forward();
48 | }
49 | });
50 | animationController?.forward();
51 | }
52 |
53 | @override
54 | void dispose() {
55 | animationController?.dispose();
56 | super.dispose();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Quiz Programming
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | quiz_programming
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
16 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/lib/presentation/pages/difficulty_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class DifficultyPage extends StatefulWidget {
4 | const DifficultyPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _DifficultyPageState();
8 | }
9 |
10 | class _DifficultyPageState extends State {
11 | final PageController pageController = PageController(initialPage: 0);
12 | int currentPage = 0;
13 |
14 | @override
15 | void initState() {
16 | super.initState();
17 | buildSlidePages();
18 | }
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | backgroundColor: AppPalette.whiteColor,
24 | body: Column(
25 | crossAxisAlignment: CrossAxisAlignment.center,
26 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
27 | children: [
28 | const DifficultyTitle(),
29 | Expanded(
30 | flex: 2,
31 | child: PageView.builder(
32 | scrollDirection: Axis.horizontal,
33 | physics: const BouncingScrollPhysics(),
34 | controller: pageController,
35 | onPageChanged: onPageChanged,
36 | itemCount: 4,
37 | itemBuilder: (ctx, i) => DifficultySlider(
38 | i,
39 | ),
40 | ),
41 | ),
42 | ],
43 | ),
44 | );
45 | }
46 |
47 | void onPageChanged(int index) {
48 | currentPage = index;
49 | }
50 |
51 | void buildSlidePages() {
52 | if (currentPage < 3) {
53 | currentPage++;
54 | } else {
55 | currentPage = 0;
56 | }
57 | if (pageController.hasClients) {
58 | pageController.animateToPage(
59 | currentPage,
60 | duration: const Duration(milliseconds: 250),
61 | curve: Curves.fastOutSlowIn,
62 | );
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:get_it/get_it.dart';
5 | import 'package:provider/provider.dart';
6 | import 'package:quiz_programming/domain/repositories/score_store_repository.dart';
7 | import 'domain/repositories/quiz_repository.dart';
8 | import 'logic/cubit/counter_cubit.dart';
9 | import 'app.dart';
10 | import 'config/constants/palette.dart';
11 | import 'domain/repositories/server_repository.dart';
12 | import 'domain/repositories/shared_preferences_store.dart';
13 | import 'domain/services/get_it/index.dart';
14 | import 'domain/services/navigation/index.dart';
15 |
16 | void main() async {
17 | WidgetsFlutterBinding.ensureInitialized();
18 | GetIt getIt = GetIt.instance;
19 | setupLocator(getIt);
20 |
21 | SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
22 | statusBarColor: AppPalette.transparentColor,
23 | ));
24 | SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
25 | overlays: [SystemUiOverlay.top]);
26 | SystemChrome.setPreferredOrientations(
27 | [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]).then((_) {
28 | runApp(
29 | MultiBlocProvider(
30 | providers: [
31 | BlocProvider(
32 | create: (_) => getIt.get(),
33 | ),
34 | ],
35 | child: MultiProvider(
36 | providers: [
37 | Provider(create: (_) => getIt.get()),
38 | Provider(create: (_) => getIt.get()),
39 | Provider(create: (_) => getIt.get()),
40 | ChangeNotifierProvider(create: (_) => getIt.get()),
41 | Provider(create: (_) => getIt.get()),
42 | ],
43 | child: const MyApp(),
44 | ),
45 | ),
46 | );
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/lib/domain/repositories/server_repository.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:http/http.dart';
4 | import 'package:provider/provider.dart';
5 | import 'package:quiz_programming/config/utils/quiz_filter_controller.dart';
6 | import 'package:quiz_programming/domain/services/navigation/index.dart';
7 | import '../../config/constants/strings.dart';
8 | import '../../data/models/response_model/quiz_response.dart';
9 |
10 | class ServerRepository {
11 | final cl = Client();
12 |
13 | //Get Quiz Data
14 | Future?> getQuizData(
15 | {required BuildContext context,
16 | required String filter,
17 | required String? category,
18 | required String? difficulty,
19 | required String? limit}) async {
20 | var param = QuizFilterController.getParams(
21 | filter: filter,
22 | category: category,
23 | difficulty: difficulty,
24 | limit: limit);
25 | final _response = await cl.get(_getParsedUri(param.toString()));
26 | if (_response.successResponse) {
27 | List? quizList = (jsonDecode(_response.body) as List)
28 | .map((e) => e == null
29 | ? null
30 | : QuizResponse.fromJson(e as Map))
31 | .toList();
32 | quizList
33 | .removeWhere((e) => e == null || e.multipleCorrectAnswers == "true");
34 | return quizList;
35 | } else {
36 | Provider.of(context, listen: false)
37 | .openErrorPage(context, withReplacement: true);
38 | return [];
39 | }
40 | }
41 |
42 | Uri _getParsedUri(String route, [Map? params]) {
43 | return Uri.parse('${AppStrings.apiHost}$route')
44 | .replace(queryParameters: params);
45 | }
46 | }
47 |
48 | extension DioResponseExtension on Response {
49 | bool get hasWrongCredentials => statusCode == 422;
50 |
51 | bool get tooManyRequests => statusCode == 429;
52 |
53 | bool get successResponse => statusCode >= 200 && statusCode < 300;
54 | }
55 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/difficulty/difficulty_slider.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class DifficultySlider extends StatefulWidget {
4 | final int index;
5 |
6 | const DifficultySlider(this.index, {Key? key}) : super(key: key);
7 |
8 | @override
9 | _DifficultySliderState createState() => _DifficultySliderState();
10 | }
11 |
12 | class _DifficultySliderState extends State {
13 | QuizRepository get quizRepo =>
14 | Provider.of(context, listen: false);
15 | final _introSliderList = [];
16 |
17 | @override
18 | void didChangeDependencies() {
19 | super.didChangeDependencies();
20 | _introSliderList.addAll(Difficulty.getDifficultyList());
21 | }
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return SingleChildScrollView(
26 | child: SizedBox(
27 | width: 90.w,
28 | child: Column(
29 | children: [
30 | Container(
31 | height: 38.h,
32 | width: 80.w,
33 | padding: EdgeInsets.only(top: 5.h),
34 | alignment: Alignment.center,
35 | color: AppPalette.transparentColor,
36 | child: SvgPicture.asset(
37 | _introSliderList[widget.index].slideImgUrl.toString())),
38 | SizedBox(
39 | height: 4.h,
40 | ),
41 | Padding(
42 | padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 1.h),
43 | child: EmphasizedButton(
44 | title: _introSliderList[widget.index].slideTitle.toString(),
45 | onButtonTap: setDifficulty),
46 | ),
47 | ],
48 | ),
49 | ),
50 | );
51 | }
52 |
53 | void setDifficulty() {
54 | quizRepo.setDifficulty(
55 | difficultyStr: _introSliderList[widget.index].slideTitle,
56 | );
57 | quizRepo.getQuizData(context);
58 | Provider.of(context, listen: false)
59 | .openQuizPage(context, withReplacement: false);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/index.dart:
--------------------------------------------------------------------------------
1 | library widgets;
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_svg/flutter_svg.dart';
5 | import 'package:percent_indicator/percent_indicator.dart';
6 | import 'package:provider/provider.dart';
7 | import 'package:quiz_programming/config/constants/assets.dart';
8 | import 'package:quiz_programming/config/constants/palette.dart';
9 | import 'package:quiz_programming/config/constants/styles.dart';
10 | import 'package:quiz_programming/config/utils/correct_answer_definer.dart';
11 | import 'package:quiz_programming/data/models/response_model/quiz_response.dart';
12 | import 'package:quiz_programming/data/models/view_model/difficulty_model.dart';
13 | import 'package:quiz_programming/data/utils/difficulty.dart';
14 | import 'package:quiz_programming/domain/repositories/quiz_repository.dart';
15 | import 'package:quiz_programming/domain/services/navigation/index.dart';
16 | import 'package:quiz_programming/logic/cubit/counter_cubit.dart';
17 | import 'package:sizer/sizer.dart';
18 | import 'dart:math' as math;
19 | part 'splash/splash_animation.dart';
20 | part 'intro/intro_button.dart';
21 | part 'intro/intro_image.dart';
22 | part 'intro/intro_title.dart';
23 | part 'buttons/counter_next_button.dart';
24 | part 'counter/counter_title.dart';
25 | part 'counter/animated_circles.dart';
26 | part 'counter/counter_value.dart';
27 | part 'counter/plasma_background.dart';
28 | part 'difficulty/difficulty_slider.dart';
29 | part 'difficulty/difficulty_title.dart';
30 | part 'quiz/question_card.dart';
31 | part 'quiz/progress_bar.dart';
32 | part 'quiz/option.dart';
33 | part 'quiz/linear_percent_show_indicator.dart';
34 | part 'buttons/emphasized_button.dart';
35 | part 'score/score_title.dart';
36 | part 'score/circular_percent_show_indicator.dart';
37 | part 'score/score_desc.dart';
38 | part 'score/score_correct_answers_title.dart';
39 | part 'score/correct_answer_checkbox_widget.dart';
40 | part 'score/correct_answers_builder.dart';
41 | part 'home/home_appbar.dart';
42 | part 'home/percentage_bubble.dart';
43 | part 'home/test_bubbles.dart';
44 | part 'home/last_activity.dart';
45 |
--------------------------------------------------------------------------------
/lib/presentation/dialogs/gesture_suggestion_dialog.dart:
--------------------------------------------------------------------------------
1 | part of dialogs;
2 |
3 | class GestureSuggestionDialog extends StatelessWidget {
4 | const GestureSuggestionDialog({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Center(
9 | child: SingleChildScrollView(
10 | child: Material(
11 | type: MaterialType.transparency,
12 | child: Container(
13 | width: 90.w,
14 | decoration: BoxDecoration(
15 | color: AppPalette.whiteColor,
16 | borderRadius: BorderRadius.circular(15),
17 | ),
18 | child: Column(
19 | mainAxisAlignment: MainAxisAlignment.center,
20 | crossAxisAlignment: CrossAxisAlignment.center,
21 | children: [
22 | Container(
23 | height: 35.h,
24 | width: 100.w,
25 | alignment: Alignment.center,
26 | color: AppPalette.transparentColor,
27 | child: Image.asset(AppImages.gestureSuggestion)),
28 | Padding(
29 | padding: AppStyles.mainPaddingStyle,
30 | child: DefaultTextStyle(
31 | style: TextStyle(
32 | color: AppPalette.homeHeadlineColor,
33 | fontSize: 18.sp,
34 | fontFamily: "Poppins",
35 | fontWeight: FontWeight.w600),
36 | child: AnimatedTextKit(
37 | isRepeatingAnimation: false,
38 | displayFullTextOnTap: true,
39 | animatedTexts: [
40 | WavyAnimatedText("Swipe left"),
41 | WavyAnimatedText("Swipe right"),
42 | WavyAnimatedText("You are good to go"),
43 | ],
44 | ),
45 | ),
46 | ),
47 | SizedBox(
48 | height: 5.h,
49 | ),
50 | ],
51 | ),
52 | ),
53 | ),
54 | ),
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/quiz/option.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class Option extends StatelessWidget {
4 | const Option({
5 | Key? key,
6 | required this.text,
7 | required this.onCheckAnswerTap,
8 | }) : super(key: key);
9 | final String? text;
10 | final VoidCallback onCheckAnswerTap;
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Consumer(builder: (context, quiz, widget) {
15 | return GestureDetector(
16 | onTap: () {
17 | onCheckAnswerTap();
18 | },
19 | child: Container(
20 | margin: EdgeInsets.only(
21 | top: 3.h,
22 | left: 6.w,
23 | right: 6.w,
24 | ),
25 | padding: AppStyles.secondaryPaddingStyle,
26 | decoration: BoxDecoration(
27 | borderRadius: BorderRadius.circular(10),
28 | color: quiz.getTheRightColor(text)),
29 | child: Row(
30 | children: [
31 | if (quiz.getTheRightColor(text) == AppPalette.homeButtonColor)
32 | Container(
33 | decoration: const BoxDecoration(
34 | shape: BoxShape.circle,
35 | color: AppPalette.homeButtonColor),
36 | child: Icon(
37 | Icons.done,
38 | size: 3.5.h,
39 | color: AppPalette.whiteColor,
40 | ),
41 | ),
42 | SizedBox(
43 | width: 5.w,
44 | ),
45 | Flexible(
46 | child: Text(
47 | text.toString(),
48 | style: TextStyle(
49 | color: quiz.getTheRightColor(text) ==
50 | AppPalette.homeButtonColor
51 | ? AppPalette.whiteColor
52 | : Colors.black,
53 | fontSize: 15.sp,
54 | fontWeight: FontWeight.w500,
55 | fontFamily: "Poppins"),
56 | ),
57 | ),
58 | ],
59 | ),
60 | ),
61 | );
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/presentation/pages/quiz_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class QuizPage extends StatelessWidget {
4 | const QuizPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Scaffold(
9 | backgroundColor: AppPalette.whiteColor,
10 | resizeToAvoidBottomInset: false,
11 | body: Consumer(
12 | builder: (context, quiz, widget) => quiz.questionsListLength == 0
13 | ? const Column(
14 | mainAxisAlignment: MainAxisAlignment.center,
15 | crossAxisAlignment: CrossAxisAlignment.center,
16 | children: [
17 | SplashAnimation(),
18 | ],
19 | )
20 | : NestedScrollView(
21 | floatHeaderSlivers: true,
22 | physics: const BouncingScrollPhysics(),
23 | headerSliverBuilder: (context, value) {
24 | return [
25 | SliverAppBar(
26 | backgroundColor: AppPalette.whiteColor,
27 | automaticallyImplyLeading: false,
28 | pinned: true,
29 | elevation: 0,
30 | expandedHeight: 2.h,
31 | floating: false,
32 | bottom: PreferredSize(
33 | preferredSize: Size.fromHeight(2.h),
34 | child: Container(),
35 | ),
36 | flexibleSpace: ProgressBar(
37 | index: quiz.currentPage,
38 | length:
39 | int.parse(quiz.questionsListLength.toString())),
40 | ),
41 | ];
42 | },
43 | body: Builder(builder: (context) {
44 | return PageView.builder(
45 | physics: const NeverScrollableScrollPhysics(),
46 | controller: quiz.pageController,
47 | onPageChanged: quiz.onPageChanged,
48 | scrollDirection: Axis.horizontal,
49 | itemCount: quiz.questionsListLength,
50 | itemBuilder: (context, i) => QuestionCard(
51 | question: quiz.questionsList?[i], questionIndex: i),
52 | );
53 | }),
54 | ),
55 | ),
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/presentation/pages/home_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class HomePage extends StatefulWidget {
4 | const HomePage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _HomePageState();
8 | }
9 |
10 | class _HomePageState extends State {
11 | NavigationService get navigation =>
12 | Provider.of(context, listen: false);
13 | QuizRepository get quizRepo =>
14 | Provider.of(context, listen: false);
15 | @override
16 | Widget build(BuildContext context) {
17 | return Scaffold(
18 | backgroundColor: AppPalette.whiteColor,
19 | body: SingleChildScrollView(
20 | physics: const BouncingScrollPhysics(),
21 | child: Column(
22 | children: [
23 | const HomeAppbar(),
24 | Consumer(
25 | builder: (context, quiz, widget) => HomePercentageBubble(
26 | onQuizTap: _continueQuiz,
27 | percentage: quiz.score,
28 | ),
29 | ),
30 | SizedBox(
31 | height: 8.h,
32 | ),
33 | TestBubbles(
34 | onCategoryTap: _categoryQuiz,
35 | onRandomTap: _randomQuiz,
36 | onTestTap: _continueQuiz,
37 | ),
38 | SizedBox(
39 | height: 5.h,
40 | ),
41 | Padding(
42 | padding: AppStyles.mainPaddingStyle,
43 | child: Row(
44 | mainAxisAlignment: MainAxisAlignment.start,
45 | children: [
46 | Text(
47 | "Last Activity",
48 | style: AppStyles.homePercentageContainerTitleStyle,
49 | ),
50 | ],
51 | ),
52 | ),
53 | SizedBox(
54 | height: 1.h,
55 | ),
56 | const LastActivity(),
57 | ],
58 | ),
59 | ),
60 | );
61 | }
62 |
63 | void _continueQuiz() {
64 | navigation.openSelectNumberOfQuestionsPage(context, withReplacement: false);
65 | }
66 |
67 | void _categoryQuiz() {
68 | quizRepo.getCategoryQuizData(context);
69 | navigation.openQuizPage(context, withReplacement: false);
70 | }
71 |
72 | void _randomQuiz() {
73 | quizRepo.getRandomQuizData(context);
74 | navigation.openQuizPage(context, withReplacement: false);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "org.jetbrains.kotlin.android"
4 | id "dev.flutter.flutter-gradle-plugin"
5 | }
6 |
7 | def localProperties = new Properties()
8 | def localPropertiesFile = rootProject.file('local.properties')
9 | if (localPropertiesFile.exists()) {
10 | localPropertiesFile.withReader('UTF-8') { reader ->
11 | localProperties.load(reader)
12 | }
13 | }
14 |
15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
16 | if (flutterVersionCode == null) {
17 | flutterVersionCode = '1'
18 | }
19 |
20 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
21 | if (flutterVersionName == null) {
22 | flutterVersionName = '1.0'
23 | }
24 |
25 | def keystoreProperties = new Properties()
26 | def keystorePropertiesFile = rootProject.file('key.properties')
27 | if (keystorePropertiesFile.exists()) {
28 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
29 | }
30 |
31 | android {
32 | namespace 'com.codequizzy_code_quizzy_app'
33 | compileSdkVersion 35
34 |
35 | compileOptions {
36 | sourceCompatibility JavaVersion.VERSION_1_8
37 | targetCompatibility JavaVersion.VERSION_1_8
38 | }
39 |
40 | kotlinOptions {
41 | jvmTarget = '1.8'
42 | }
43 |
44 | sourceSets {
45 | main.java.srcDirs += 'src/main/kotlin'
46 | }
47 |
48 | defaultConfig {
49 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
50 | applicationId "com.codequizzy_code_quizzy_app"
51 | minSdkVersion flutter.minSdkVersion
52 | targetSdkVersion 35
53 | versionCode flutterVersionCode.toInteger()
54 | versionName flutterVersionName
55 | multiDexEnabled true
56 | }
57 |
58 | signingConfigs {
59 | release {
60 | keyAlias keystoreProperties['keyAlias']
61 | keyPassword keystoreProperties['keyPassword']
62 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
63 | storePassword keystoreProperties['storePassword']
64 | }
65 | }
66 | buildTypes {
67 | release {
68 | signingConfig signingConfigs.release
69 | }
70 | }
71 | }
72 |
73 | flutter {
74 | source '../..'
75 | }
76 |
77 | dependencies {
78 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20"
79 | implementation 'com.google.android.material:material:1.6.1'
80 | implementation("androidx.multidex:multidex:2.0.1")
81 | }
82 |
--------------------------------------------------------------------------------
/lib/presentation/pages/score_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class ScorePage extends StatefulWidget {
4 | const ScorePage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _ScorePageState();
8 | }
9 |
10 | class _ScorePageState extends State {
11 | void _goToHome() => Provider.of(context, listen: false)
12 | .openHomePage(context, withReplacement: true);
13 | @override
14 | Widget build(BuildContext context) {
15 | return Scaffold(
16 | backgroundColor: AppPalette.whiteColor,
17 | body: SingleChildScrollView(
18 | scrollDirection: Axis.vertical,
19 | physics: const BouncingScrollPhysics(),
20 | child: Column(
21 | children: [
22 | Padding(
23 | padding: EdgeInsets.only(top: 8.h, left: 6.w, right: 6.w),
24 | child: Row(
25 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
26 | children: [
27 | const ScoreTitle(),
28 | IconButton(
29 | onPressed: _goToHome,
30 | icon: Icon(
31 | Icons.restart_alt_outlined,
32 | size: 4.5.h,
33 | color: AppPalette.headlineFourthColor,
34 | ))
35 | ],
36 | ),
37 | ),
38 | SizedBox(
39 | height: 6.h,
40 | ),
41 | Consumer(
42 | builder: (context, quiz, widget) => Padding(
43 | padding: AppStyles.mainPaddingStyle,
44 | child: Row(
45 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
46 | children: [
47 | CircularPercentShowIndicator(
48 | percent: quiz.numOfCorrectAns / quiz.questionsListLength!,
49 | ),
50 | ScoreDesc(
51 | percentage:
52 | quiz.numOfCorrectAns / quiz.questionsListLength!,
53 | ),
54 | ],
55 | ),
56 | ),
57 | ),
58 | SizedBox(
59 | height: 6.h,
60 | ),
61 | const ScoreCorrectAnswersTitle(),
62 | SizedBox(
63 | height: 2.h,
64 | ),
65 | const CorrectAnswersBuilder(),
66 | SizedBox(
67 | height: 4.h,
68 | ),
69 | ],
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/domain/services/navigation/service.dart:
--------------------------------------------------------------------------------
1 | part of navigation;
2 |
3 | class NavigationService {
4 | static final navigationKey = GlobalKey();
5 |
6 | const NavigationService();
7 |
8 | void openSplashPage(BuildContext context, {bool withReplacement = false}) =>
9 | withReplacement
10 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.splash)
11 | : Navigator.pushNamed(context, NavigationRoutes.splash);
12 | void openIntroPage(BuildContext context, {bool withReplacement = false}) =>
13 | withReplacement
14 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.intro)
15 | : Navigator.pushNamed(context, NavigationRoutes.intro);
16 |
17 | void openHomePage(BuildContext context, {bool withReplacement = false}) =>
18 | withReplacement
19 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.home)
20 | : Navigator.pushNamed(context, NavigationRoutes.home);
21 | void openSelectNumberOfQuestionsPage(BuildContext context,
22 | {bool withReplacement = false}) =>
23 | withReplacement
24 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.counter)
25 | : Navigator.pushNamed(context, NavigationRoutes.counter);
26 | void openTopicSelectionPage(BuildContext context,
27 | {bool withReplacement = false}) =>
28 | withReplacement
29 | ? Navigator.pushReplacementNamed(
30 | context, NavigationRoutes.topicSelection)
31 | : Navigator.pushNamed(context, NavigationRoutes.topicSelection);
32 | void openDifficultyPage(BuildContext context,
33 | {bool withReplacement = false}) =>
34 | withReplacement
35 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.difficulty)
36 | : Navigator.pushNamed(context, NavigationRoutes.difficulty);
37 | void openQuizPage(BuildContext context, {bool withReplacement = false}) =>
38 | withReplacement
39 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.quizPage)
40 | : Navigator.pushNamed(context, NavigationRoutes.quizPage);
41 |
42 | void openScorePage(BuildContext context, {bool withReplacement = false}) =>
43 | withReplacement
44 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.scorePage)
45 | : Navigator.pushNamed(context, NavigationRoutes.scorePage);
46 | void openErrorPage(BuildContext context, {bool withReplacement = false}) =>
47 | withReplacement
48 | ? Navigator.pushReplacementNamed(context, NavigationRoutes.errorPage)
49 | : Navigator.pushNamed(context, NavigationRoutes.errorPage);
50 |
51 | void back(BuildContext context, {dynamic result}) =>
52 | Navigator.pop(context, result);
53 | }
54 |
--------------------------------------------------------------------------------
/lib/presentation/pages/counter_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class CounterPage extends StatefulWidget {
4 | const CounterPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | _CounterPageState createState() => _CounterPageState();
8 | }
9 |
10 | class _CounterPageState extends State {
11 | String? counterValue;
12 |
13 | @override
14 | void initState() {
15 | super.initState();
16 | _checkFirstSeen();
17 | }
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | counterValue = context
22 | .select((CounterCubit counterCubit) => counterCubit.state.counterValue)
23 | .toString();
24 | return Scaffold(
25 | backgroundColor: AppPalette.whiteColor,
26 | body: Swipe(
27 | onSwipeLeft: () {
28 | context.read().decrement();
29 | },
30 | onSwipeRight: () {
31 | context.read().increment();
32 | },
33 | child: Column(
34 | children: [
35 | Padding(
36 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 6.h),
37 | child: CounterNextButton(
38 | nextPress: _openTopicSelectionPage,
39 | ),
40 | ),
41 | SizedBox(
42 | height: 6.h,
43 | ),
44 | const CounterTitle(),
45 | Stack(
46 | alignment: Alignment.center,
47 | children: [
48 | const PlasmaBackground(),
49 | Positioned(
50 | top: 15.0.h,
51 | child: AnimatedCircles(
52 | counterValue: int.tryParse(counterValue ?? '3') ?? 3,
53 | onIncrement: () =>
54 | context.read().increment(),
55 | onDecrement: () =>
56 | context.read().decrement(),
57 | ),
58 | ),
59 | ],
60 | ),
61 | ],
62 | ),
63 | ));
64 | }
65 |
66 | Future _checkFirstSeen() async {
67 | final _seen =
68 | await Provider.of(context, listen: false)
69 | .getFirstSeen();
70 | if (_seen == true) return;
71 | Future.delayed(const Duration(seconds: 1), () {
72 | showGestureSuggestionDialog(context);
73 | });
74 | }
75 |
76 | void _openTopicSelectionPage() {
77 | Provider.of(context, listen: false).setNumOfQuestions(
78 | counterValue: counterValue,
79 | );
80 | Provider.of(context, listen: false).setFirstSeen();
81 | Provider.of(context, listen: false)
82 | .openTopicSelectionPage(context, withReplacement: false);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/quiz/question_card.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class QuestionCard extends StatelessWidget {
4 | const QuestionCard({
5 | Key? key,
6 | required this.question,
7 | required this.questionIndex,
8 | }) : super(key: key);
9 |
10 | final QuizResponse? question;
11 | final int? questionIndex;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | var index = questionIndex;
16 | var data = question!;
17 | var answers = data.answers!;
18 | return SingleChildScrollView(
19 | child: Consumer(
20 | builder: (context, quiz, widget) => Column(
21 | children: [
22 | Padding(
23 | padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 3.h),
24 | child: Text(
25 | data.question!,
26 | textAlign: TextAlign.center,
27 | style: AppStyles.quizQuestionTextStyle,
28 | ),
29 | ),
30 | if (answers.answerA != null)
31 | Option(
32 | onCheckAnswerTap: () => quiz.checkAns(answers.answerA!, index!),
33 | text: answers.answerA.toString(),
34 | ),
35 | if (answers.answerB != null)
36 | Option(
37 | onCheckAnswerTap: () => quiz.checkAns(answers.answerB!, index!),
38 | text: answers.answerB.toString(),
39 | ),
40 | if (answers.answerC != null)
41 | Option(
42 | onCheckAnswerTap: () => quiz.checkAns(answers.answerC!, index!),
43 | text: answers.answerC.toString(),
44 | ),
45 | if (answers.answerD != null)
46 | Option(
47 | onCheckAnswerTap: () =>
48 | quiz.checkAns(data.answers!.answerD!, index!),
49 | text: data.answers?.answerD.toString(),
50 | ),
51 | if (data.answers!.answerE != null)
52 | Option(
53 | onCheckAnswerTap: () => quiz.checkAns(answers.answerE!, index!),
54 | text: answers.answerE.toString(),
55 | ),
56 | if (answers.answerF != null)
57 | Option(
58 | onCheckAnswerTap: () => quiz.checkAns(answers.answerF!, index!),
59 | text: answers.answerF.toString(),
60 | ),
61 | Padding(
62 | padding: AppStyles.mainPaddingStyle,
63 | child: EmphasizedButton(
64 | onButtonTap: () {
65 | quiz.nextQuestion(
66 | context: context, index: int.parse(index.toString()));
67 | },
68 | title: "Next",
69 | )),
70 | SizedBox(
71 | height: 4.h,
72 | ),
73 | ],
74 | ),
75 | ),
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/assets/images/gesture_show.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
50 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/presentation/pages/error_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class ErrorPage extends StatefulWidget {
4 | const ErrorPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _ErrorPageState();
8 | }
9 |
10 | class _ErrorPageState extends State {
11 | void _comeBack() =>
12 | Provider.of(context, listen: false).back(context);
13 | @override
14 | Widget build(BuildContext context) {
15 | return Scaffold(
16 | backgroundColor: AppPalette.whiteColor,
17 | body: Column(
18 | mainAxisAlignment: MainAxisAlignment.center,
19 | children: [
20 | Container(
21 | height: 27.h,
22 | width: 85.w,
23 | alignment: Alignment.center,
24 | color: AppPalette.transparentColor,
25 | child: Image.asset(AppImages.failureImage)),
26 | Padding(
27 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 2.h),
28 | child: Center(
29 | child: Text(
30 | "Server Problem",
31 | textAlign: TextAlign.center,
32 | style: TextStyle(
33 | color: AppPalette.headlineFourthColor,
34 | fontWeight: FontWeight.bold,
35 | fontFamily: "Gotham Pro",
36 | fontSize: 20.2.sp,
37 | height: 1.7,
38 | ),
39 | ),
40 | ),
41 | ),
42 | Padding(
43 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 3.h),
44 | child: Center(
45 | child: Text(
46 | "Check your connection, please come back again",
47 | textAlign: TextAlign.center,
48 | style: TextStyle(
49 | color: AppPalette.blueGrey,
50 | fontWeight: FontWeight.bold,
51 | fontFamily: "Poppins",
52 | fontSize: 13.2.sp,
53 | height: 1.5,
54 | ),
55 | ),
56 | ),
57 | ),
58 | Padding(
59 | padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 4.h),
60 | child: Container(
61 | height: 7.4.h,
62 | width: double.infinity,
63 | decoration: BoxDecoration(
64 | color: const Color.fromRGBO(250, 125, 130, 1),
65 | borderRadius: BorderRadius.circular(10),
66 | ),
67 | child: Material(
68 | color: Colors.transparent,
69 | child: InkWell(
70 | onTap: () {
71 | _comeBack();
72 | },
73 | child: Padding(
74 | padding: const EdgeInsets.all(5.0),
75 | child: Center(
76 | child: Text(
77 | "Back",
78 | style: TextStyle(
79 | color: AppPalette.whiteColor,
80 | fontWeight: FontWeight.bold,
81 | fontFamily: "Poppins",
82 | fontSize: 17.8.sp,
83 | ),
84 | ),
85 | )),
86 | ),
87 | ),
88 | ),
89 | ),
90 | ],
91 | ),
92 | );
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
42 |
43 |
55 |
57 |
63 |
64 |
65 |
66 |
72 |
74 |
80 |
81 |
82 |
83 |
85 |
86 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/score/correct_answers_builder.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class CorrectAnswersBuilder extends StatelessWidget {
4 | const CorrectAnswersBuilder({
5 | Key? key,
6 | }) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Consumer(
11 | builder: (context, quiz, widget) => MediaQuery.removePadding(
12 | context: context,
13 | removeTop: true,
14 | removeBottom: true,
15 | child: ListView.builder(
16 | physics: const BouncingScrollPhysics(),
17 | itemCount: quiz.questionsListLength,
18 | scrollDirection: Axis.vertical,
19 | shrinkWrap: true,
20 | itemBuilder: (context, index) {
21 | var correctAnswer = CorrectAnswerDefiner.getCorrectAnswer(
22 | index: index, questionsList: quiz.questionsList);
23 | var topic = quiz.questionsList?[index]?.category;
24 | return Padding(
25 | padding: AppStyles.scoreListviewPaddingStyle,
26 | child: SizedBox(
27 | height: 20.h,
28 | child: Row(
29 | mainAxisAlignment: MainAxisAlignment.start,
30 | children: [
31 | Container(
32 | height: 3.h,
33 | width: 3.h,
34 | decoration: AppStyles.mainBoxDecorationStyle,
35 | ),
36 | SizedBox(
37 | width: 10.w,
38 | ),
39 | Stack(
40 | clipBehavior: Clip.none,
41 | alignment: Alignment.topRight,
42 | children: [
43 | Container(
44 | height: 15.h,
45 | width: 40.w,
46 | decoration:
47 | AppStyles.scoreAnswersBoxDecorationStyle,
48 | child: Column(
49 | mainAxisAlignment:
50 | MainAxisAlignment.spaceBetween,
51 | crossAxisAlignment: CrossAxisAlignment.start,
52 | children: [
53 | Padding(
54 | padding: EdgeInsets.only(
55 | left: 4.w, top: 1.h, right: 4.w),
56 | child: Text(
57 | "${index + 1}. ${topic.toString()}",
58 | style: AppStyles
59 | .scoreCorrectAnswerCategoryStyle,
60 | ),
61 | ),
62 | Padding(
63 | padding: EdgeInsets.only(
64 | left: 4.w, bottom: 1.h, right: 4.w),
65 | child: Text(
66 | "$correctAnswer",
67 | overflow: TextOverflow.ellipsis,
68 | maxLines: 2,
69 | style:
70 | AppStyles.scoreCorrectAnswerDessStyle,
71 | ),
72 | )
73 | ],
74 | )),
75 | const CorrectAnswerCheckboxWidget(),
76 | ],
77 | ),
78 | ],
79 | ),
80 | ),
81 | );
82 | }),
83 | ),
84 | );
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/home/percentage_bubble.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class HomePercentageBubble extends StatelessWidget {
4 | const HomePercentageBubble({
5 | Key? key,
6 | required this.percentage,
7 | required this.onQuizTap,
8 | }) : super(key: key);
9 | final double? percentage;
10 | final VoidCallback onQuizTap;
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Padding(
15 | padding: AppStyles.mainPaddingStyle,
16 | child: SingleChildScrollView(
17 | child: Stack(
18 | alignment: Alignment.bottomCenter,
19 | clipBehavior: Clip.none,
20 | children: [
21 | Container(
22 | width: double.infinity,
23 | padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 6.h),
24 | decoration: BoxDecoration(
25 | color: AppPalette.homeContainerColor,
26 | borderRadius: BorderRadius.circular(50)),
27 | child: Row(
28 | crossAxisAlignment: CrossAxisAlignment.center,
29 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
30 | children: [
31 | buildPercentIndicator(),
32 | SizedBox(
33 | width: 45.w,
34 | child: RichText(
35 | text: TextSpan(children: [
36 | TextSpan(
37 | text: percentage! > 50
38 | ? "Good Result!\n\n"
39 | : "Bad Result!\n\n",
40 | style: AppStyles.homePercentageContainerTitleStyle,
41 | ),
42 | TextSpan(
43 | text: percentage! > 50
44 | ? "Your 👨💻 has been improved."
45 | : "Your 👨💻 has been deteriorated.",
46 | style: AppStyles.homePercentageContainerDescStyle,
47 | ),
48 | ]),
49 | ),
50 | ),
51 | ],
52 | ),
53 | ),
54 | Positioned(
55 | bottom: -2.5.h,
56 | child: InkWell(
57 | onTap: onQuizTap,
58 | child: Container(
59 | decoration: BoxDecoration(
60 | color: AppPalette.homeButtonColor,
61 | borderRadius: BorderRadius.circular(15)),
62 | height: 6.h,
63 | width: 48.w,
64 | child: Row(
65 | mainAxisAlignment: MainAxisAlignment.center,
66 | crossAxisAlignment: CrossAxisAlignment.center,
67 | children: [
68 | Icon(
69 | Icons.play_arrow_rounded,
70 | color: AppPalette.whiteColor,
71 | size: 4.h,
72 | ),
73 | SizedBox(
74 | width: 3.w,
75 | ),
76 | Text(
77 | "Continue",
78 | style: TextStyle(
79 | color: AppPalette.whiteColor,
80 | fontFamily: "Poppins",
81 | fontSize: 13.sp,
82 | fontWeight: FontWeight.bold),
83 | )
84 | ],
85 | ),
86 | ),
87 | )),
88 | ],
89 | ),
90 | ),
91 | );
92 | }
93 |
94 | CircularPercentIndicator buildPercentIndicator() {
95 | return CircularPercentIndicator(
96 | radius: 5.5.h,
97 | lineWidth: 17.0,
98 | animation: true,
99 | animationDuration: 1500,
100 | percent: percentage! / 100,
101 | center: Text(
102 | percentage!.toStringAsFixed(0) + "%",
103 | style: AppStyles.homePercentageTextStyle,
104 | ),
105 | backgroundColor: AppPalette.progressBarColor,
106 | circularStrokeCap: CircularStrokeCap.round,
107 | progressColor: AppPalette.homeButtonColor,
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | quiz_programming
33 |
34 |
35 |
36 |
39 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/home/test_bubbles.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class TestBubbles extends StatelessWidget {
4 | const TestBubbles({
5 | Key? key,
6 | required this.onCategoryTap,
7 | required this.onRandomTap,
8 | required this.onTestTap,
9 | }) : super(key: key);
10 | final VoidCallback onCategoryTap;
11 | final VoidCallback onRandomTap;
12 | final VoidCallback onTestTap;
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Padding(
17 | padding: AppStyles.mainPaddingStyle,
18 | child: Row(
19 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
20 | children: [
21 | Column(
22 | children: [
23 | InkWell(
24 | onTap: onCategoryTap,
25 | child: Container(
26 | height: 14.h,
27 | width: 46.w,
28 | decoration: AppStyles.homeCategoryBoxdecorationStyle,
29 | child: Column(
30 | mainAxisAlignment: MainAxisAlignment.center,
31 | crossAxisAlignment: CrossAxisAlignment.center,
32 | children: [
33 | Container(
34 | height: 4.h,
35 | width: 14.w,
36 | color: AppPalette.transparentColor,
37 | child: Image.asset(AppImages.categoryImage)),
38 | SizedBox(
39 | height: 1.5.h,
40 | ),
41 | Center(
42 | child: Text(
43 | "Category\n",
44 | textAlign: TextAlign.center,
45 | style: AppStyles.homeBubblesTextStyle,
46 | ),
47 | ),
48 | ],
49 | ),
50 | ),
51 | ),
52 | SizedBox(
53 | height: 3.h,
54 | ),
55 | InkWell(
56 | onTap: onRandomTap,
57 | child: Container(
58 | height: 14.h,
59 | width: 45.w,
60 | decoration: AppStyles.homeRandomTestDecorationStyle,
61 | child: Column(
62 | mainAxisAlignment: MainAxisAlignment.center,
63 | crossAxisAlignment: CrossAxisAlignment.center,
64 | children: [
65 | Container(
66 | height: 4.h,
67 | width: 14.w,
68 | color: AppPalette.transparentColor,
69 | child: Image.asset(AppImages.randomTestImage)),
70 | SizedBox(
71 | height: 1.5.h,
72 | ),
73 | Center(
74 | child: Text(
75 | "Random Quiz\n",
76 | textAlign: TextAlign.center,
77 | style: AppStyles.homeBubblesTextStyle,
78 | ),
79 | ),
80 | ],
81 | ),
82 | ),
83 | ),
84 | ],
85 | ),
86 | InkWell(
87 | onTap: onTestTap,
88 | child: Container(
89 | height: 31.h,
90 | width: 38.w,
91 | decoration: AppStyles.homeTakeTestDecorationStyle,
92 | child: Column(
93 | mainAxisAlignment: MainAxisAlignment.center,
94 | crossAxisAlignment: CrossAxisAlignment.center,
95 | children: [
96 | Container(
97 | height: 8.h,
98 | width: 30.w,
99 | color: AppPalette.transparentColor,
100 | child: Image.asset(AppImages.takeTestImage)),
101 | SizedBox(
102 | height: 3.h,
103 | ),
104 | Center(
105 | child: Text(
106 | "Take a Test!\n",
107 | textAlign: TextAlign.center,
108 | style: AppStyles.homeBubblesTextStyle,
109 | ),
110 | ),
111 | ],
112 | ),
113 | ),
114 | ),
115 | ],
116 | ),
117 | );
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/lib/data/models/response_model/quiz_response.dart:
--------------------------------------------------------------------------------
1 | class QuizResponse {
2 | int? id;
3 | String? question;
4 | dynamic description;
5 | Answers? answers;
6 | String? multipleCorrectAnswers;
7 | CorrectAnswers? correctAnswers;
8 | String? correctAnswer;
9 | dynamic explanation;
10 | dynamic tip;
11 | List? tags;
12 | String? category;
13 | String? difficulty;
14 |
15 | QuizResponse(
16 | {this.id,
17 | this.question,
18 | this.description,
19 | this.answers,
20 | this.multipleCorrectAnswers,
21 | this.correctAnswers,
22 | this.correctAnswer,
23 | this.explanation,
24 | this.tip,
25 | this.tags,
26 | this.category,
27 | this.difficulty});
28 |
29 | QuizResponse.fromJson(Map json) {
30 | id = json['id'];
31 | question = json['question'];
32 | description = json['description'];
33 | answers =
34 | json['answers'] != null ? Answers.fromJson(json['answers']) : null;
35 | multipleCorrectAnswers = json['multiple_correct_answers'];
36 | correctAnswers = json['correct_answers'] != null
37 | ? CorrectAnswers.fromJson(json['correct_answers'])
38 | : null;
39 | correctAnswer = json['correct_answer'];
40 | explanation = json['explanation'];
41 | tip = json['tip'];
42 | if (json['tags'] != null) {
43 | tags = [];
44 | json['tags'].forEach((v) {
45 | tags!.add(Tags.fromJson(v));
46 | });
47 | }
48 | category = json['category'];
49 | difficulty = json['difficulty'];
50 | }
51 |
52 | Map toJson() {
53 | final Map data = {};
54 | data['id'] = id;
55 | data['question'] = question;
56 | data['description'] = description;
57 | if (answers != null) {
58 | data['answers'] = answers!.toJson();
59 | }
60 | data['multiple_correct_answers'] = multipleCorrectAnswers;
61 | if (correctAnswers != null) {
62 | data['correct_answers'] = correctAnswers!.toJson();
63 | }
64 | data['correct_answer'] = correctAnswer;
65 | data['explanation'] = explanation;
66 | data['tip'] = tip;
67 | if (tags != null) {
68 | data['tags'] = tags!.map((v) => v.toJson()).toList();
69 | }
70 | data['category'] = category;
71 | data['difficulty'] = difficulty;
72 | return data;
73 | }
74 | }
75 |
76 | class Answers {
77 | String? answerA;
78 | String? answerB;
79 | String? answerC;
80 | String? answerD;
81 | String? answerE;
82 | String? answerF;
83 |
84 | Answers(
85 | {this.answerA,
86 | this.answerB,
87 | this.answerC,
88 | this.answerD,
89 | this.answerE,
90 | this.answerF});
91 |
92 | Answers.fromJson(Map json) {
93 | answerA = json['answer_a'];
94 | answerB = json['answer_b'];
95 | answerC = json['answer_c'];
96 | answerD = json['answer_d'];
97 | answerE = json['answer_e'];
98 | answerF = json['answer_f'];
99 | }
100 |
101 | Map toJson() {
102 | final Map data = {};
103 | data['answer_a'] = answerA;
104 | data['answer_b'] = answerB;
105 | data['answer_c'] = answerC;
106 | data['answer_d'] = answerD;
107 | data['answer_e'] = answerE;
108 | data['answer_f'] = answerF;
109 | return data;
110 | }
111 | }
112 |
113 | class CorrectAnswers {
114 | String? answerACorrect;
115 | String? answerBCorrect;
116 | String? answerCCorrect;
117 | String? answerDCorrect;
118 | String? answerECorrect;
119 | String? answerFCorrect;
120 |
121 | CorrectAnswers(
122 | {this.answerACorrect,
123 | this.answerBCorrect,
124 | this.answerCCorrect,
125 | this.answerDCorrect,
126 | this.answerECorrect,
127 | this.answerFCorrect});
128 |
129 | CorrectAnswers.fromJson(Map json) {
130 | answerACorrect = json['answer_a_correct'];
131 | answerBCorrect = json['answer_b_correct'];
132 | answerCCorrect = json['answer_c_correct'];
133 | answerDCorrect = json['answer_d_correct'];
134 | answerECorrect = json['answer_e_correct'];
135 | answerFCorrect = json['answer_f_correct'];
136 | }
137 |
138 | Map toJson() {
139 | final Map data = {};
140 | data['answer_a_correct'] = answerACorrect;
141 | data['answer_b_correct'] = answerBCorrect;
142 | data['answer_c_correct'] = answerCCorrect;
143 | data['answer_d_correct'] = answerDCorrect;
144 | data['answer_e_correct'] = answerECorrect;
145 | data['answer_f_correct'] = answerFCorrect;
146 | return data;
147 | }
148 | }
149 |
150 | class Tags {
151 | String? name;
152 |
153 | Tags({this.name});
154 |
155 | Tags.fromJson(Map json) {
156 | name = json['name'];
157 | }
158 |
159 | Map toJson() {
160 | final Map data = {};
161 | data['name'] = name;
162 | return data;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/lib/presentation/pages/topic_selection_page.dart:
--------------------------------------------------------------------------------
1 | part of pages;
2 |
3 | class TopicSelectionPage extends StatefulWidget {
4 | const TopicSelectionPage({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _TopicSelectionPageState();
8 | }
9 |
10 | class _TopicSelectionPageState extends State {
11 | List topicsList = [];
12 | int listIndex = 0;
13 |
14 | @override
15 | void didChangeDependencies() {
16 | topicsList.addAll(Topics.getAllTopics());
17 | super.didChangeDependencies();
18 | }
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | backgroundColor: AppPalette.whiteColor,
24 | body: SingleChildScrollView(
25 | physics: const BouncingScrollPhysics(),
26 | child: Column(
27 | crossAxisAlignment: CrossAxisAlignment.center,
28 | children: [
29 | Padding(
30 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 6.h),
31 | child: CounterNextButton(nextPress: () {
32 | _openDifficultyPage();
33 | }),
34 | ),
35 | Padding(
36 | padding: EdgeInsets.only(left: 6.w, right: 6.w, top: 6.h),
37 | child: Text(
38 | "Which topic do you want to choose?\n",
39 | textAlign: TextAlign.center,
40 | style: AppStyles.counterTitleTextStyle,
41 | ),
42 | ),
43 | GridView.builder(
44 | padding: AppStyles.secondaryPaddingStyle,
45 | shrinkWrap: true,
46 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
47 | crossAxisCount: 2,
48 | crossAxisSpacing: 15,
49 | childAspectRatio: 100.w / (100.h / 1.8),
50 | mainAxisSpacing: 15),
51 | physics: const BouncingScrollPhysics(),
52 | scrollDirection: Axis.vertical,
53 | itemCount: topicsList.length,
54 | itemBuilder: (context, index) {
55 | return InkWell(
56 | onTap: () {
57 | setState(() {
58 | for (var element in topicsList) {
59 | element.isSelected = false;
60 | }
61 | topicsList[index].isSelected = true;
62 | listIndex = index;
63 | });
64 | },
65 | child: AnimatedContainer(
66 | duration: const Duration(milliseconds: 400),
67 | decoration: BoxDecoration(
68 | boxShadow: [
69 | AppStyles.topicContainerShadow,
70 | ],
71 | color: topicsList[index].isSelected
72 | ? AppPalette.homeButtonColor
73 | : AppPalette.whiteColor,
74 | borderRadius: BorderRadius.circular(10),
75 | ),
76 | child: Column(
77 | mainAxisAlignment: MainAxisAlignment.center,
78 | crossAxisAlignment: CrossAxisAlignment.center,
79 | children: [
80 | Column(
81 | children: [
82 | ZoomIn(
83 | duration: const Duration(seconds: 2),
84 | child: Container(
85 | height: 10.h,
86 | width: 15.w,
87 | alignment: Alignment.center,
88 | color: AppPalette.transparentColor,
89 | child: Image.asset(
90 | topicsList[index].imgUrl.toString()),
91 | ),
92 | ),
93 | Text(topicsList[index].title.toString(),
94 | textAlign: TextAlign.center,
95 | style: TextStyle(
96 | fontSize: 17.sp,
97 | fontFamily: "Poppins",
98 | fontWeight: FontWeight.bold,
99 | color: topicsList[index].isSelected
100 | ? AppPalette.whiteColor
101 | : AppPalette.homeHeadlineColor,
102 | )),
103 | ],
104 | ),
105 | ],
106 | ),
107 | ),
108 | );
109 | }),
110 | SizedBox(
111 | height: 5.h,
112 | ),
113 | ],
114 | ),
115 | ),
116 | );
117 | }
118 |
119 | void _openDifficultyPage() {
120 | Provider.of(context, listen: false).setTopic(
121 | topicStr: topicsList[listIndex].title,
122 | );
123 |
124 | Provider.of(context, listen: false).setImage(
125 | imgUrl: topicsList[listIndex].imgUrl,
126 | );
127 | Provider.of(context, listen: false)
128 | .openDifficultyPage(context, withReplacement: true);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/lib/domain/repositories/quiz_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:provider/provider.dart';
3 | import '../../config/constants/palette.dart';
4 | import '../../config/utils/correct_answer_definer.dart';
5 | import '../../data/models/response_model/quiz_response.dart';
6 | import 'score_store_repository.dart';
7 | import 'server_repository.dart';
8 | import '../services/navigation/index.dart';
9 |
10 | class QuizRepository with ChangeNotifier {
11 | QuizRepository(this._serverRepository);
12 | final ServerRepository _serverRepository;
13 | final PageController pageController = PageController();
14 | List? questionsList = [];
15 | List? scoreCredentials;
16 | int? questionsListLength = 0;
17 | int currentPage = 1;
18 | String? topicImage;
19 | String? numOfQuestions;
20 | String? topic;
21 | String? difficulty;
22 | String? correctAns = '';
23 | String? selectedAns;
24 | double? score;
25 | int _numOfCorrectAns = 0;
26 | int get numOfCorrectAns => _numOfCorrectAns;
27 | bool? _isAnswered = false;
28 | bool get isAnswered => _isAnswered!;
29 |
30 | void onPageChanged(int index) {
31 | currentPage = index + 1;
32 | notifyListeners();
33 | }
34 |
35 | void nextQuestion({required BuildContext context, required int index}) {
36 | if (correctAns == selectedAns) _numOfCorrectAns++;
37 | if (currentPage != questionsListLength!) {
38 | _isAnswered = false;
39 | if (pageController.hasClients) {
40 | pageController.animateToPage(
41 | currentPage,
42 | duration: const Duration(milliseconds: 250),
43 | curve: Curves.fastOutSlowIn,
44 | );
45 | }
46 | } else {
47 | score = ((numOfCorrectAns / questionsListLength!) * 100)
48 | ..toStringAsFixed(2);
49 | var provider = Provider.of(context, listen: false);
50 | provider.setQuizScore(score);
51 | provider.setScoreCredentials(
52 | category: topic.toString(), imgUrl: topicImage.toString());
53 | Provider.of(context, listen: false)
54 | .openScorePage(context, withReplacement: true);
55 | }
56 | notifyListeners();
57 | }
58 |
59 | void checkAns(String selectedAnswer, int selectedIndex) {
60 | selectedAns = selectedAnswer;
61 | _isAnswered = true;
62 | correctAns = CorrectAnswerDefiner.getCorrectAnswer(
63 | index: selectedIndex, questionsList: questionsList);
64 | notifyListeners();
65 | }
66 |
67 | Future getQuizData(BuildContext context) async {
68 | questionsList = [];
69 | questionsListLength = 0;
70 | currentPage = 1;
71 | _numOfCorrectAns = 0;
72 | correctAns = '';
73 | selectedAns;
74 | questionsList = await _serverRepository.getQuizData(
75 | context: context,
76 | filter: 'normal_quiz',
77 | category: topic,
78 | difficulty: difficulty,
79 | limit: numOfQuestions);
80 | questionsListLength = questionsList?.length;
81 | notifyListeners();
82 | }
83 |
84 | Future getRandomQuizData(BuildContext context) async {
85 | _clearQuizList();
86 | correctAns = '';
87 | selectedAns;
88 | questionsList = await _serverRepository.getQuizData(
89 | context: context,
90 | filter: 'random_quiz',
91 | category: '',
92 | difficulty: '',
93 | limit: '');
94 | questionsListLength = questionsList?.length;
95 | notifyListeners();
96 | }
97 |
98 | Future getCategoryQuizData(BuildContext context) async {
99 | _clearQuizList();
100 | correctAns = '';
101 | selectedAns;
102 | questionsList = await _serverRepository.getQuizData(
103 | context: context,
104 | filter: 'category_quiz',
105 | category: topic,
106 | difficulty: difficulty,
107 | limit: numOfQuestions);
108 | questionsListLength = questionsList?.length;
109 | notifyListeners();
110 | }
111 |
112 | Future getLastQuizScore(BuildContext context) async {
113 | score = await Provider.of(context, listen: false)
114 | .quizLastScore;
115 | notifyListeners();
116 | }
117 |
118 | Future getScoreCredentials(BuildContext context) async {
119 | var provider = Provider.of(context, listen: false);
120 | final _lastScore = await provider.quizLastScore;
121 | if (_lastScore != null) {
122 | topic = await provider.category;
123 | topicImage = await provider.imgUrl;
124 | }
125 | notifyListeners();
126 | }
127 |
128 | void setNumOfQuestions({required String? counterValue}) {
129 | numOfQuestions = counterValue;
130 | notifyListeners();
131 | }
132 |
133 | void setTopic({required String? topicStr}) {
134 | topic = topicStr?.toLowerCase().capitalize();
135 | notifyListeners();
136 | }
137 |
138 | void setImage({required String? imgUrl}) {
139 | topicImage = imgUrl;
140 | notifyListeners();
141 | }
142 |
143 | void setDifficulty({required String? difficultyStr}) {
144 | difficulty = difficultyStr?.toLowerCase();
145 | notifyListeners();
146 | }
147 |
148 | void _clearQuizList() {
149 | questionsList = [];
150 | questionsListLength = 0;
151 | currentPage = 1;
152 | numOfQuestions = '0';
153 | _numOfCorrectAns = 0;
154 | }
155 |
156 | //Getting the right color in case answered question
157 | Color getTheRightColor(String? selectedAnswer) {
158 | if (isAnswered) {
159 | if (selectedAns == selectedAnswer) {
160 | return AppPalette.homeButtonColor;
161 | } else {
162 | return AppPalette.progressBarColor;
163 | }
164 | } else {
165 | return AppPalette.progressBarColor;
166 | }
167 | }
168 | }
169 |
170 | extension StringExtension on String {
171 | String capitalize() {
172 | return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/counter/animated_circles.dart:
--------------------------------------------------------------------------------
1 | part of widgets;
2 |
3 | class AnimatedCircles extends StatelessWidget {
4 | final int counterValue;
5 | final VoidCallback onIncrement;
6 | final VoidCallback onDecrement;
7 |
8 | const AnimatedCircles({
9 | Key? key,
10 | required this.counterValue,
11 | required this.onIncrement,
12 | required this.onDecrement,
13 | }) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Container(
18 | color: AppPalette.whiteColor,
19 | width: 70.0.w,
20 | height: deviceTablet ? 33.0.h : 28.h,
21 | child: CounterCircleAnimation(
22 | number: counterValue,
23 | onIncrement: onIncrement,
24 | onDecrement: onDecrement,
25 | ));
26 | }
27 | }
28 |
29 | class CounterCircleAnimation extends StatefulWidget {
30 | final int number;
31 | final VoidCallback onIncrement;
32 | final VoidCallback onDecrement;
33 |
34 | const CounterCircleAnimation({
35 | Key? key,
36 | required this.number,
37 | required this.onIncrement,
38 | required this.onDecrement,
39 | }) : super(key: key);
40 |
41 | @override
42 | _CounterCircleAnimationState createState() => _CounterCircleAnimationState();
43 | }
44 |
45 | class _CounterCircleAnimationState extends State
46 | with TickerProviderStateMixin {
47 | late AnimationController _pulseController;
48 | late AnimationController _rotateController;
49 | late Animation _pulseAnimation;
50 | late Animation _rotateAnimation;
51 |
52 | @override
53 | void initState() {
54 | super.initState();
55 |
56 | // Pulse animation for the main circle
57 | _pulseController = AnimationController(
58 | duration: const Duration(seconds: 2),
59 | vsync: this,
60 | );
61 |
62 | // Rotation animation for decorative elements
63 | _rotateController = AnimationController(
64 | duration: const Duration(seconds: 8),
65 | vsync: this,
66 | );
67 |
68 | _pulseAnimation = Tween(begin: 0.95, end: 1.05).animate(
69 | CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
70 | );
71 |
72 | _rotateAnimation = Tween(begin: 0, end: 2 * math.pi).animate(
73 | CurvedAnimation(parent: _rotateController, curve: Curves.linear),
74 | );
75 |
76 | _startAnimations();
77 | }
78 |
79 | void _startAnimations() {
80 | _pulseController.repeat(reverse: true);
81 | _rotateController.repeat();
82 | }
83 |
84 | @override
85 | Widget build(BuildContext context) {
86 | return AnimatedBuilder(
87 | animation: Listenable.merge([_pulseController, _rotateController]),
88 | builder: (context, child) {
89 | return Stack(
90 | alignment: Alignment.center,
91 | children: [
92 | // Rotating decorative circles
93 | Transform.rotate(
94 | angle: _rotateAnimation.value,
95 | child: Container(
96 | width: 60.w,
97 | height: 60.w,
98 | decoration: BoxDecoration(
99 | shape: BoxShape.circle,
100 | border: Border.all(
101 | color: AppPalette.homeButtonColor.withOpacity(0.1),
102 | width: 1,
103 | ),
104 | ),
105 | child: Stack(
106 | children: [
107 | // Small decorative dots
108 | Positioned(
109 | top: 0,
110 | left: 50.w * 0.5 - 2,
111 | child: Container(
112 | width: 4,
113 | height: 4,
114 | decoration: BoxDecoration(
115 | shape: BoxShape.circle,
116 | color: AppPalette.homeButtonColor.withOpacity(0.6),
117 | ),
118 | ),
119 | ),
120 | Positioned(
121 | bottom: 0,
122 | left: 50.w * 0.5 - 2,
123 | child: Container(
124 | width: 4,
125 | height: 4,
126 | decoration: BoxDecoration(
127 | shape: BoxShape.circle,
128 | color: AppPalette.homeButtonColor.withOpacity(0.6),
129 | ),
130 | ),
131 | ),
132 | ],
133 | ),
134 | ),
135 | ),
136 |
137 | // Main counter circle with pulse animation
138 | Transform.scale(
139 | scale: _pulseAnimation.value,
140 | child: Container(
141 | width: 35.w,
142 | height: 35.w,
143 | decoration: BoxDecoration(
144 | shape: BoxShape.circle,
145 | color: AppPalette.homeButtonColor,
146 | boxShadow: [
147 | BoxShadow(
148 | color: AppPalette.homeButtonColor.withOpacity(0.3),
149 | blurRadius: 20,
150 | spreadRadius: 5,
151 | ),
152 | ],
153 | ),
154 | child: Center(
155 | child: Text(
156 | widget.number.toString(),
157 | style: TextStyle(
158 | color: AppPalette.whiteColor,
159 | fontSize: 32.sp,
160 | fontWeight: FontWeight.bold,
161 | fontFamily: "Poppins",
162 | ),
163 | ),
164 | ),
165 | ),
166 | ),
167 |
168 | // Plus button (top right)
169 | Positioned(
170 | top: 8.h,
171 | right: 8.w,
172 | child: GestureDetector(
173 | onTap: widget.onIncrement,
174 | child: Container(
175 | width: 12.w,
176 | height: 12.w,
177 | decoration: BoxDecoration(
178 | shape: BoxShape.circle,
179 | color: AppPalette.homeButtonColor,
180 | boxShadow: [
181 | BoxShadow(
182 | color: AppPalette.homeButtonColor.withOpacity(0.3),
183 | blurRadius: 8,
184 | spreadRadius: 2,
185 | ),
186 | ],
187 | ),
188 | child: Icon(
189 | Icons.add,
190 | color: AppPalette.whiteColor,
191 | size: 6.w,
192 | ),
193 | ),
194 | ),
195 | ),
196 |
197 | // Minus button (bottom left)
198 | Positioned(
199 | bottom: 8.h,
200 | left: 8.w,
201 | child: GestureDetector(
202 | onTap: widget.onDecrement,
203 | child: Container(
204 | width: 12.w,
205 | height: 12.w,
206 | decoration: BoxDecoration(
207 | shape: BoxShape.circle,
208 | color: AppPalette.homeButtonColor,
209 | boxShadow: [
210 | BoxShadow(
211 | color: AppPalette.homeButtonColor.withOpacity(0.3),
212 | blurRadius: 8,
213 | spreadRadius: 2,
214 | ),
215 | ],
216 | ),
217 | child: Icon(
218 | Icons.remove,
219 | color: AppPalette.whiteColor,
220 | size: 6.w,
221 | ),
222 | ),
223 | ),
224 | ),
225 | ],
226 | );
227 | },
228 | );
229 | }
230 |
231 | @override
232 | void dispose() {
233 | _pulseController.dispose();
234 | _rotateController.dispose();
235 | super.dispose();
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/lib/config/constants/styles.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:sizer/sizer.dart';
3 | import 'palette.dart';
4 |
5 | final bool deviceTablet = SizerUtil.deviceType == DeviceType.tablet;
6 |
7 | abstract class AppStyles {
8 | static const gothamProRegularFontFamily = "Gotham Pro";
9 | static const gothamProBoldFontFamily = "Gotham Pro Bold";
10 | static const poppinsRegularFontFamily = "Poppins";
11 | static final homeTitleTextStyle = TextStyle(
12 | color: AppPalette.homeHeadlineColor,
13 | fontFamily: gothamProBoldFontFamily,
14 | height: 1.7,
15 | letterSpacing: 1.5,
16 | fontWeight: FontWeight.bold,
17 | fontSize: 18.sp);
18 | static final homeButtonTextStyle = TextStyle(
19 | color: AppPalette.whiteColor,
20 | fontFamily: gothamProBoldFontFamily,
21 | letterSpacing: 1.5,
22 | fontWeight: FontWeight.bold,
23 | fontSize: 18.sp);
24 |
25 | static final difficultyButtonStyle = TextStyle(
26 | color: AppPalette.whiteColor,
27 | fontFamily: gothamProBoldFontFamily,
28 | letterSpacing: 1.5,
29 | fontWeight: FontWeight.bold,
30 | fontSize: 15.sp);
31 |
32 | static final counterNextButtonStyle = TextStyle(
33 | color: AppPalette.homeHeadlineColor,
34 | fontFamily: poppinsRegularFontFamily,
35 | fontSize: 17.sp,
36 | fontWeight: FontWeight.w600);
37 |
38 | static final counterTitleTextStyle = TextStyle(
39 | fontSize: 19.sp,
40 | height: 1.6,
41 | fontFamily: poppinsRegularFontFamily,
42 | fontWeight: FontWeight.bold,
43 | color: AppPalette.homeHeadlineColor,
44 | );
45 |
46 | static final counterDescTextStyle = TextStyle(
47 | height: 2.5,
48 | fontFamily: poppinsRegularFontFamily,
49 | fontSize: 13.sp,
50 | fontWeight: FontWeight.bold,
51 | color: AppPalette.greyColor,
52 | );
53 |
54 | static final difficultyDescStyle = TextStyle(
55 | height: 1.6,
56 | fontFamily: poppinsRegularFontFamily,
57 | fontSize: 13.sp,
58 | fontWeight: FontWeight.bold,
59 | color: AppPalette.greyColor,
60 | );
61 |
62 | static final topicContainerShadow = BoxShadow(
63 | color: AppPalette.greyColor.withOpacity(0.3),
64 | spreadRadius: 2,
65 | blurRadius: 7,
66 | offset: const Offset(0, 3),
67 | );
68 |
69 | static final quizProgressBarIndexStyle = TextStyle(
70 | fontSize: 14.sp,
71 | fontFamily: gothamProRegularFontFamily,
72 | fontWeight: FontWeight.bold,
73 | color: AppPalette.homeButtonColor);
74 |
75 | static final quizProgressBarLengthStyle = TextStyle(
76 | fontFamily: poppinsRegularFontFamily,
77 | fontSize: 11.sp,
78 | fontWeight: FontWeight.w500,
79 | color: AppPalette.headlineFourthColor);
80 |
81 | static final quizQuestionTextStyle = TextStyle(
82 | fontSize: 17.sp,
83 | fontWeight: FontWeight.w500,
84 | height: 1.5,
85 | fontFamily: poppinsRegularFontFamily,
86 | color: AppPalette.headlineFourthColor);
87 |
88 | static final scoreTitleTextStyle = TextStyle(
89 | color: AppPalette.headlineFourthColor,
90 | height: 1.9,
91 | fontSize: 24.sp,
92 | fontWeight: FontWeight.bold,
93 | fontFamily: gothamProBoldFontFamily);
94 |
95 | static final scorePercentageTitleStyle = TextStyle(
96 | fontSize: 13.sp,
97 | fontFamily: poppinsRegularFontFamily,
98 | fontWeight: FontWeight.bold,
99 | color: AppPalette.greyColor);
100 |
101 | static final scorePercentageDescTextStyle = TextStyle(
102 | height: 1.8,
103 | fontFamily: gothamProRegularFontFamily,
104 | fontSize: 28.sp,
105 | fontWeight: FontWeight.bold,
106 | color: AppPalette.headlineFourthColor);
107 |
108 | static final scoreWrongAnswersTitleStyle = TextStyle(
109 | fontFamily: gothamProRegularFontFamily,
110 | fontSize: 14.sp,
111 | fontWeight: FontWeight.bold,
112 | color: AppPalette.headlineFourthColor);
113 |
114 | static final scoreCorrectAnswerCategoryStyle = TextStyle(
115 | fontSize: 13.sp,
116 | fontFamily: poppinsRegularFontFamily,
117 | fontWeight: FontWeight.bold,
118 | color: AppPalette.greyColor);
119 |
120 | static final scoreCorrectAnswerDessStyle = TextStyle(
121 | fontSize: 13.sp,
122 | fontFamily: gothamProRegularFontFamily,
123 | fontWeight: FontWeight.bold,
124 | color: AppPalette.headlineFourthColor);
125 |
126 | static final mainPaddingStyle = EdgeInsets.symmetric(horizontal: 6.w);
127 | static final secondaryPaddingStyle =
128 | EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h);
129 | static final scoreListviewPaddingStyle = EdgeInsets.only(left: 6.w);
130 | static final mainBoxDecorationStyle = BoxDecoration(boxShadow: [
131 | BoxShadow(
132 | color: AppPalette.headlineThirdColor.withOpacity(0.5),
133 | spreadRadius: 2,
134 | blurRadius: 7,
135 | offset: const Offset(0, 3),
136 | ),
137 | ], color: AppPalette.headlineThirdColor, shape: BoxShape.circle);
138 |
139 | static final scoreAnswersBoxDecorationStyle = BoxDecoration(boxShadow: [
140 | BoxShadow(
141 | color: AppPalette.greyColor.withOpacity(0.2),
142 | spreadRadius: 2,
143 | blurRadius: 7,
144 | offset: const Offset(0, 3),
145 | ),
146 | ], borderRadius: BorderRadius.circular(15), color: AppPalette.whiteColor);
147 |
148 | static final scoreWrongAnswerDecorationStyle = BoxDecoration(boxShadow: [
149 | BoxShadow(
150 | color: AppPalette.errorColor.withOpacity(0.5),
151 | spreadRadius: 2,
152 | blurRadius: 7,
153 | offset: const Offset(0, 3),
154 | ),
155 | ], color: AppPalette.errorColor, shape: BoxShape.circle);
156 |
157 | static final homeCategoryBoxdecorationStyle = BoxDecoration(
158 | boxShadow: [
159 | BoxShadow(
160 | color: AppPalette.homeCategoryBackColor.withOpacity(0.4),
161 | spreadRadius: 2,
162 | blurRadius: 7,
163 | offset: const Offset(0, 3),
164 | ),
165 | ],
166 | color: AppPalette.homeCategoryBackColor,
167 | borderRadius: BorderRadius.circular(25));
168 |
169 | static final homeRandomTestDecorationStyle = BoxDecoration(
170 | boxShadow: [
171 | BoxShadow(
172 | color: AppPalette.homeRandomTestBackColor.withOpacity(0.4),
173 | spreadRadius: 2,
174 | blurRadius: 7,
175 | offset: const Offset(0, 3),
176 | ),
177 | ],
178 | color: AppPalette.homeRandomTestBackColor,
179 | borderRadius: BorderRadius.circular(25));
180 |
181 | static final homeTakeTestDecorationStyle = BoxDecoration(
182 | boxShadow: [
183 | BoxShadow(
184 | color: AppPalette.homeTakeTestBackColor.withOpacity(0.4),
185 | spreadRadius: 2,
186 | blurRadius: 7,
187 | offset: const Offset(0, 3),
188 | ),
189 | ],
190 | color: AppPalette.homeTakeTestBackColor,
191 | borderRadius: BorderRadius.circular(25));
192 |
193 | static final homePercentageTextStyle = TextStyle(
194 | color: AppPalette.headlineFourthColor,
195 | fontFamily: poppinsRegularFontFamily,
196 | fontWeight: FontWeight.bold,
197 | fontSize: 10.sp);
198 |
199 | static final homePercentageContainerTitleStyle = TextStyle(
200 | color: AppPalette.homeHeadlineColor,
201 | fontFamily: gothamProBoldFontFamily,
202 | fontSize: 15.sp,
203 | fontWeight: FontWeight.bold,
204 | );
205 |
206 | static final homePercentageContainerDescStyle = TextStyle(
207 | height: 1.8,
208 | fontFamily: poppinsRegularFontFamily,
209 | fontSize: 11.sp,
210 | fontWeight: FontWeight.bold,
211 | color: AppPalette.greyColor,
212 | );
213 |
214 | static final homeBubblesTextStyle = TextStyle(
215 | color: AppPalette.homeHeadlineColor,
216 | fontFamily: gothamProBoldFontFamily,
217 | fontSize: 13.sp,
218 | fontWeight: FontWeight.bold,
219 | );
220 |
221 | static final lastActivityHomeTopicTextStyle = TextStyle(
222 | color: AppPalette.headlineFourthColor,
223 | fontFamily: gothamProRegularFontFamily,
224 | fontSize: 14.sp,
225 | fontWeight: FontWeight.bold,
226 | );
227 |
228 | static final lastActivityHomeScoreTextStyle = TextStyle(
229 | color: AppPalette.greenColor,
230 | fontFamily: gothamProRegularFontFamily,
231 | fontSize: 14.sp,
232 | fontWeight: FontWeight.bold,
233 | );
234 | }
235 |
--------------------------------------------------------------------------------
/assets/images/difficulty/any_difficulty.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | animate_do:
5 | dependency: "direct main"
6 | description:
7 | name: animate_do
8 | sha256: "4554744e604b841e2bde710398ef3f4f8a1935a182b48727afe2a1023527b883"
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.1.0"
12 | animated_text_kit:
13 | dependency: "direct main"
14 | description:
15 | name: animated_text_kit
16 | sha256: adba517adb7e6adeb1eb5e1c8a147dd7bc664dfdf2f5e92226b572a91393a93d
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "4.2.3"
20 | archive:
21 | dependency: transitive
22 | description:
23 | name: archive
24 | sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "3.6.1"
28 | args:
29 | dependency: transitive
30 | description:
31 | name: args
32 | sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "2.7.0"
36 | async:
37 | dependency: transitive
38 | description:
39 | name: async
40 | sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "2.13.0"
44 | bloc:
45 | dependency: transitive
46 | description:
47 | name: bloc
48 | sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "8.1.4"
52 | boolean_selector:
53 | dependency: transitive
54 | description:
55 | name: boolean_selector
56 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "2.1.2"
60 | characters:
61 | dependency: transitive
62 | description:
63 | name: characters
64 | sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "1.4.0"
68 | clock:
69 | dependency: transitive
70 | description:
71 | name: clock
72 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
73 | url: "https://pub.dev"
74 | source: hosted
75 | version: "1.1.2"
76 | collection:
77 | dependency: transitive
78 | description:
79 | name: collection
80 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
81 | url: "https://pub.dev"
82 | source: hosted
83 | version: "1.19.1"
84 | crypto:
85 | dependency: transitive
86 | description:
87 | name: crypto
88 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
89 | url: "https://pub.dev"
90 | source: hosted
91 | version: "3.0.6"
92 | cupertino_icons:
93 | dependency: "direct main"
94 | description:
95 | name: cupertino_icons
96 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
97 | url: "https://pub.dev"
98 | source: hosted
99 | version: "1.0.8"
100 | fake_async:
101 | dependency: transitive
102 | description:
103 | name: fake_async
104 | sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
105 | url: "https://pub.dev"
106 | source: hosted
107 | version: "1.3.3"
108 | ffi:
109 | dependency: transitive
110 | description:
111 | name: ffi
112 | sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
113 | url: "https://pub.dev"
114 | source: hosted
115 | version: "2.1.4"
116 | file:
117 | dependency: transitive
118 | description:
119 | name: file
120 | sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
121 | url: "https://pub.dev"
122 | source: hosted
123 | version: "7.0.1"
124 | flutter:
125 | dependency: "direct main"
126 | description: flutter
127 | source: sdk
128 | version: "0.0.0"
129 | flutter_bloc:
130 | dependency: "direct main"
131 | description:
132 | name: flutter_bloc
133 | sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
134 | url: "https://pub.dev"
135 | source: hosted
136 | version: "8.1.6"
137 | flutter_launcher_icons:
138 | dependency: "direct dev"
139 | description:
140 | name: flutter_launcher_icons
141 | sha256: "559c600f056e7c704bd843723c21e01b5fba47e8824bd02422165bcc02a5de1d"
142 | url: "https://pub.dev"
143 | source: hosted
144 | version: "0.9.3"
145 | flutter_lints:
146 | dependency: "direct dev"
147 | description:
148 | name: flutter_lints
149 | sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493
150 | url: "https://pub.dev"
151 | source: hosted
152 | version: "1.0.4"
153 | flutter_svg:
154 | dependency: "direct main"
155 | description:
156 | name: flutter_svg
157 | sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2"
158 | url: "https://pub.dev"
159 | source: hosted
160 | version: "1.1.6"
161 | flutter_test:
162 | dependency: "direct dev"
163 | description: flutter
164 | source: sdk
165 | version: "0.0.0"
166 | flutter_web_plugins:
167 | dependency: transitive
168 | description: flutter
169 | source: sdk
170 | version: "0.0.0"
171 | get_it:
172 | dependency: "direct main"
173 | description:
174 | name: get_it
175 | sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
176 | url: "https://pub.dev"
177 | source: hosted
178 | version: "7.7.0"
179 | http:
180 | dependency: "direct main"
181 | description:
182 | name: http
183 | sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
184 | url: "https://pub.dev"
185 | source: hosted
186 | version: "0.13.6"
187 | http_parser:
188 | dependency: transitive
189 | description:
190 | name: http_parser
191 | sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
192 | url: "https://pub.dev"
193 | source: hosted
194 | version: "4.1.2"
195 | image:
196 | dependency: transitive
197 | description:
198 | name: image
199 | sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
200 | url: "https://pub.dev"
201 | source: hosted
202 | version: "3.3.0"
203 | leak_tracker:
204 | dependency: transitive
205 | description:
206 | name: leak_tracker
207 | sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
208 | url: "https://pub.dev"
209 | source: hosted
210 | version: "10.0.9"
211 | leak_tracker_flutter_testing:
212 | dependency: transitive
213 | description:
214 | name: leak_tracker_flutter_testing
215 | sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
216 | url: "https://pub.dev"
217 | source: hosted
218 | version: "3.0.9"
219 | leak_tracker_testing:
220 | dependency: transitive
221 | description:
222 | name: leak_tracker_testing
223 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
224 | url: "https://pub.dev"
225 | source: hosted
226 | version: "3.0.1"
227 | lints:
228 | dependency: transitive
229 | description:
230 | name: lints
231 | sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
232 | url: "https://pub.dev"
233 | source: hosted
234 | version: "1.0.1"
235 | matcher:
236 | dependency: transitive
237 | description:
238 | name: matcher
239 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
240 | url: "https://pub.dev"
241 | source: hosted
242 | version: "0.12.17"
243 | material_color_utilities:
244 | dependency: transitive
245 | description:
246 | name: material_color_utilities
247 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
248 | url: "https://pub.dev"
249 | source: hosted
250 | version: "0.11.1"
251 | meta:
252 | dependency: transitive
253 | description:
254 | name: meta
255 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
256 | url: "https://pub.dev"
257 | source: hosted
258 | version: "1.16.0"
259 | nested:
260 | dependency: transitive
261 | description:
262 | name: nested
263 | sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
264 | url: "https://pub.dev"
265 | source: hosted
266 | version: "1.0.0"
267 | path:
268 | dependency: transitive
269 | description:
270 | name: path
271 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
272 | url: "https://pub.dev"
273 | source: hosted
274 | version: "1.9.1"
275 | path_drawing:
276 | dependency: transitive
277 | description:
278 | name: path_drawing
279 | sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
280 | url: "https://pub.dev"
281 | source: hosted
282 | version: "1.0.1"
283 | path_parsing:
284 | dependency: transitive
285 | description:
286 | name: path_parsing
287 | sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
288 | url: "https://pub.dev"
289 | source: hosted
290 | version: "1.1.0"
291 | path_provider_linux:
292 | dependency: transitive
293 | description:
294 | name: path_provider_linux
295 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
296 | url: "https://pub.dev"
297 | source: hosted
298 | version: "2.2.1"
299 | path_provider_platform_interface:
300 | dependency: transitive
301 | description:
302 | name: path_provider_platform_interface
303 | sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
304 | url: "https://pub.dev"
305 | source: hosted
306 | version: "2.1.2"
307 | path_provider_windows:
308 | dependency: transitive
309 | description:
310 | name: path_provider_windows
311 | sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
312 | url: "https://pub.dev"
313 | source: hosted
314 | version: "2.3.0"
315 | percent_indicator:
316 | dependency: "direct main"
317 | description:
318 | name: percent_indicator
319 | sha256: "157d29133bbc6ecb11f923d36e7960a96a3f28837549a20b65e5135729f0f9fd"
320 | url: "https://pub.dev"
321 | source: hosted
322 | version: "4.2.5"
323 | petitparser:
324 | dependency: transitive
325 | description:
326 | name: petitparser
327 | sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
328 | url: "https://pub.dev"
329 | source: hosted
330 | version: "7.0.1"
331 | platform:
332 | dependency: transitive
333 | description:
334 | name: platform
335 | sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
336 | url: "https://pub.dev"
337 | source: hosted
338 | version: "3.1.6"
339 | plugin_platform_interface:
340 | dependency: transitive
341 | description:
342 | name: plugin_platform_interface
343 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
344 | url: "https://pub.dev"
345 | source: hosted
346 | version: "2.1.8"
347 | provider:
348 | dependency: "direct main"
349 | description:
350 | name: provider
351 | sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
352 | url: "https://pub.dev"
353 | source: hosted
354 | version: "6.1.5"
355 | shared_preferences:
356 | dependency: "direct main"
357 | description:
358 | name: shared_preferences
359 | sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
360 | url: "https://pub.dev"
361 | source: hosted
362 | version: "2.5.3"
363 | shared_preferences_android:
364 | dependency: transitive
365 | description:
366 | name: shared_preferences_android
367 | sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
368 | url: "https://pub.dev"
369 | source: hosted
370 | version: "2.4.11"
371 | shared_preferences_foundation:
372 | dependency: transitive
373 | description:
374 | name: shared_preferences_foundation
375 | sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
376 | url: "https://pub.dev"
377 | source: hosted
378 | version: "2.5.4"
379 | shared_preferences_linux:
380 | dependency: transitive
381 | description:
382 | name: shared_preferences_linux
383 | sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
384 | url: "https://pub.dev"
385 | source: hosted
386 | version: "2.4.1"
387 | shared_preferences_platform_interface:
388 | dependency: transitive
389 | description:
390 | name: shared_preferences_platform_interface
391 | sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
392 | url: "https://pub.dev"
393 | source: hosted
394 | version: "2.4.1"
395 | shared_preferences_web:
396 | dependency: transitive
397 | description:
398 | name: shared_preferences_web
399 | sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
400 | url: "https://pub.dev"
401 | source: hosted
402 | version: "2.4.3"
403 | shared_preferences_windows:
404 | dependency: transitive
405 | description:
406 | name: shared_preferences_windows
407 | sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
408 | url: "https://pub.dev"
409 | source: hosted
410 | version: "2.4.1"
411 | sizer:
412 | dependency: "direct main"
413 | description:
414 | name: sizer
415 | sha256: d2b3cb6cbc4a637f508dacd786bae55df31e5fc088044248a43e4fd1e050c117
416 | url: "https://pub.dev"
417 | source: hosted
418 | version: "2.0.15"
419 | sky_engine:
420 | dependency: transitive
421 | description: flutter
422 | source: sdk
423 | version: "0.0.0"
424 | source_span:
425 | dependency: transitive
426 | description:
427 | name: source_span
428 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
429 | url: "https://pub.dev"
430 | source: hosted
431 | version: "1.10.1"
432 | stack_trace:
433 | dependency: transitive
434 | description:
435 | name: stack_trace
436 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
437 | url: "https://pub.dev"
438 | source: hosted
439 | version: "1.12.1"
440 | stream_channel:
441 | dependency: transitive
442 | description:
443 | name: stream_channel
444 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
445 | url: "https://pub.dev"
446 | source: hosted
447 | version: "2.1.4"
448 | string_scanner:
449 | dependency: transitive
450 | description:
451 | name: string_scanner
452 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
453 | url: "https://pub.dev"
454 | source: hosted
455 | version: "1.4.1"
456 | swipe:
457 | dependency: "direct main"
458 | description:
459 | name: swipe
460 | sha256: e2f823093ef0161698cc380f5f868a6be380cb5c90c1c0ddc7fa2b0a7eadfa0e
461 | url: "https://pub.dev"
462 | source: hosted
463 | version: "0.0.1"
464 | term_glyph:
465 | dependency: transitive
466 | description:
467 | name: term_glyph
468 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
469 | url: "https://pub.dev"
470 | source: hosted
471 | version: "1.2.2"
472 | test_api:
473 | dependency: transitive
474 | description:
475 | name: test_api
476 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
477 | url: "https://pub.dev"
478 | source: hosted
479 | version: "0.7.4"
480 | typed_data:
481 | dependency: transitive
482 | description:
483 | name: typed_data
484 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
485 | url: "https://pub.dev"
486 | source: hosted
487 | version: "1.4.0"
488 | universal_io:
489 | dependency: transitive
490 | description:
491 | name: universal_io
492 | sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
493 | url: "https://pub.dev"
494 | source: hosted
495 | version: "2.2.2"
496 | vector_math:
497 | dependency: transitive
498 | description:
499 | name: vector_math
500 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
501 | url: "https://pub.dev"
502 | source: hosted
503 | version: "2.1.4"
504 | vm_service:
505 | dependency: transitive
506 | description:
507 | name: vm_service
508 | sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
509 | url: "https://pub.dev"
510 | source: hosted
511 | version: "15.0.0"
512 | web:
513 | dependency: transitive
514 | description:
515 | name: web
516 | sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
517 | url: "https://pub.dev"
518 | source: hosted
519 | version: "1.1.1"
520 | xdg_directories:
521 | dependency: transitive
522 | description:
523 | name: xdg_directories
524 | sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
525 | url: "https://pub.dev"
526 | source: hosted
527 | version: "1.1.0"
528 | xml:
529 | dependency: transitive
530 | description:
531 | name: xml
532 | sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
533 | url: "https://pub.dev"
534 | source: hosted
535 | version: "6.6.1"
536 | yaml:
537 | dependency: transitive
538 | description:
539 | name: yaml
540 | sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
541 | url: "https://pub.dev"
542 | source: hosted
543 | version: "3.1.3"
544 | sdks:
545 | dart: ">=3.8.0 <4.0.0"
546 | flutter: ">=3.27.0"
547 |
--------------------------------------------------------------------------------