├── 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 | ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/iamnijat/code-quizzy/Flutter%20CI/master) 2 | ![GitHub forks](https://img.shields.io/github/forks/iamnijat/code-quizzy) 3 | ![GitHub stars](https://img.shields.io/github/stars/iamnijat/code-quizzy) 4 | ![GitHub watchers](https://img.shields.io/github/watchers/iamnijat/code-quizzy) 5 | ![GitHub contributors](https://img.shields.io/github/contributors/iamnijat/code-quizzy) 6 | ![GitHub last commit](https://img.shields.io/github/last-commit/iamnijat/code-quizzy) 7 | ![GitHub top language](https://img.shields.io/github/languages/top/iamnijat/code-quizzy) 8 | 9 | # Flutter Code Quizzy Application 10 | 11 | 12 | ![mockup](https://user-images.githubusercontent.com/42466886/151920669-91c23fbb-d38a-4401-a865-c65ffece840a.png) 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 | 7 | 8 | 10 | 21 | 24 | 26 | 28 | 32 | 48 | 49 | 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 | positive_attitude -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------