Full Code of joaomanaia/newquiz for AI

main c6f3748ce80e cached
659 files
2.2 MB
613.2k tokens
1 requests
Download .txt
Showing preview only (2,485K chars total). Download the full file or copy to clipboard to get everything.
Repository: joaomanaia/newquiz
Branch: main
Commit: c6f3748ce80e
Files: 659
Total size: 2.2 MB

Directory structure:
gitextract_3fcvki05/

├── .github/
│   ├── actions/
│   │   └── get-avd-info/
│   │       └── action.yml
│   └── workflows/
│       ├── android.yml
│       └── android_old.yml
├── .gitignore
├── LICENCE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── lint-baseline.xml
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── AndroidManifest.xml
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── infinitepower/
│           │           └── newquiz/
│           │               ├── NewQuizApp.kt
│           │               ├── core/
│           │               │   ├── navigation/
│           │               │   │   ├── AppNavGraphs.kt
│           │               │   │   ├── CommonNavGraphNavigator.kt
│           │               │   │   └── NavigationItem.kt
│           │               │   └── workers/
│           │               │       └── AppStartLoggingAnalyticsWorker.kt
│           │               ├── initializer/
│           │               │   ├── EnqueueStartWorksInitializer.kt
│           │               │   └── WorkManagerInitializer.kt
│           │               └── ui/
│           │                   ├── components/
│           │                   │   ├── DataCollectionConsentDialog.kt
│           │                   │   └── DiamondsCounter.kt
│           │                   ├── main/
│           │                   │   ├── MainActivity.kt
│           │                   │   ├── MainScreenUiEvent.kt
│           │                   │   ├── MainScreenUiState.kt
│           │                   │   └── MainViewModel.kt
│           │                   └── navigation/
│           │                       ├── CompactNavigationContainer.kt
│           │                       ├── ExpandedNavigationContainer.kt
│           │                       ├── MediumNavigationContainer.kt
│           │                       ├── NavDrawerContent.kt
│           │                       └── NavigationContainer.kt
│           └── res/
│               ├── drawable/
│               │   ├── round_password_24.xml
│               │   ├── round_play_circle_24.xml
│               │   └── round_quiz_24.xml
│               ├── resources.properties
│               ├── values/
│               │   ├── colors.xml
│               │   ├── leak_canary.xml
│               │   ├── splash_screen.xml
│               │   └── strings.xml
│               ├── values-night/
│               │   └── splash_screen.xml
│               └── xml-v25/
│                   └── shortcuts.xml
├── build-logic/
│   ├── .gitignore
│   ├── README.md
│   ├── convention/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               ├── AndroidApplicationComposeConventionPlugin.kt
│   │               ├── AndroidApplicationConventionPlugin.kt
│   │               ├── AndroidApplicationFirebaseConventionPlugin.kt
│   │               ├── AndroidComposeDestinationsConventionPlugin.kt
│   │               ├── AndroidFeatureConventionPlugin.kt
│   │               ├── AndroidHiltConventionPlugin.kt
│   │               ├── AndroidLibraryComposeConventionPlugin.kt
│   │               ├── AndroidLibraryConventionPlugin.kt
│   │               ├── AndroidRoomConventionPlugin.kt
│   │               ├── DetektConventionPlugin.kt
│   │               ├── JvmLibraryConventionPlugin.kt
│   │               ├── KotlinSerializationConventionPlugin.kt
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           ├── AndroidCompose.kt
│   │                           ├── AndroidInstrumentedTests.kt
│   │                           ├── Flavors.kt
│   │                           ├── KotlinAndroid.kt
│   │                           ├── ProjectConfig.kt
│   │                           ├── ProjectExtensions.kt
│   │                           └── Utils.kt
│   ├── gradle.properties
│   └── settings.gradle.kts
├── build.gradle.kts
├── comparison-quiz/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── comparison_quiz/
│       │                       ├── data/
│       │                       │   └── comparison_quiz/
│       │                       │       └── FakeComparisonQuizRepositoryImpl.kt
│       │                       ├── list/
│       │                       │   └── components/
│       │                       │       ├── ComparisonModeComponentTest.kt
│       │                       │       └── ComparisonModeComponentsTest.kt
│       │                       └── ui/
│       │                           ├── ComparisonQuizScreenTest.kt
│       │                           └── components/
│       │                               └── ComparisonItemTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── comparison_quiz/
│       │                       ├── core/
│       │                       │   ├── ComparisonQuizCoreImpl.kt
│       │                       │   └── workers/
│       │                       │       └── ComparisonQuizEndGameWorker.kt
│       │                       ├── di/
│       │                       │   └── ComparisonQuizModule.kt
│       │                       ├── list/
│       │                       │   ├── ComparisonQuizListScreen.kt
│       │                       │   ├── ComparisonQuizListScreenUiEvent.kt
│       │                       │   ├── ComparisonQuizListScreenUiState.kt
│       │                       │   ├── ComparisonQuizListScreenViewModel.kt
│       │                       │   └── components/
│       │                       │       ├── ComparisonModeComponent.kt
│       │                       │       └── ComparisonModeComponents.kt
│       │                       └── ui/
│       │                           ├── AnimationState.kt
│       │                           ├── ComparisonQuizScreen.kt
│       │                           ├── ComparisonQuizUiEvent.kt
│       │                           ├── ComparisonQuizUiState.kt
│       │                           ├── ComparisonQuizViewModel.kt
│       │                           └── components/
│       │                               ├── ComparisonItem.kt
│       │                               ├── ComparisonMidContent.kt
│       │                               ├── GameOverContent.kt
│       │                               └── MiddleCircle.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── comparison_quiz/
│                               └── core/
│                                   └── ComparisonQuizCoreImplTest.kt
├── compose_compiler_config.conf
├── core/
│   ├── .gitignore
│   ├── analytics/
│   │   ├── .gitignore
│   │   ├── LOGGING_ANALYTICS.md
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── analytics/
│   │       │                           └── FossAnalyticsModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── analytics/
│   │       │                           ├── AnalyticsEvent.kt
│   │       │                           ├── AnalyticsHelper.kt
│   │       │                           ├── LocalDebugAnalyticsHelper.kt
│   │       │                           ├── NoOpAnalyticsHelper.kt
│   │       │                           ├── UiHelpers.kt
│   │       │                           └── UserProperty.kt
│   │       └── normal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── analytics/
│   │                                   ├── FirebaseAnalyticsHelper.kt
│   │                                   └── NormalAnalyticsModule.kt
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── database/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   ├── schemas/
│   │   │   └── com.infinitepower.newquiz.core.database.AppDatabase/
│   │   │       ├── 1.json
│   │   │       ├── 2.json
│   │   │       ├── 3.json
│   │   │       ├── 4.json
│   │   │       ├── 5.json
│   │   │       ├── 6.json
│   │   │       └── 7.json
│   │   └── src/
│   │       ├── androidTest/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── database/
│   │       │                           └── dao/
│   │       │                               └── DailyChallengeDaoTest.kt
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── database/
│   │                                   ├── AppDatabase.kt
│   │                                   ├── dao/
│   │                                   │   ├── DailyChallengeDao.kt
│   │                                   │   ├── GameResultDao.kt
│   │                                   │   ├── MazeQuizDao.kt
│   │                                   │   └── SavedMultiChoiceQuestionsDao.kt
│   │                                   ├── di/
│   │                                   │   ├── DaoModule.kt
│   │                                   │   └── DatabaseModule.kt
│   │                                   ├── model/
│   │                                   │   ├── DailyChallengeTaskEntity.kt
│   │                                   │   ├── MazeQuizItemEntity.kt
│   │                                   │   ├── MultiChoiceQuestionEntity.kt
│   │                                   │   └── user/
│   │                                   │       ├── BaseGameResultEntity.kt
│   │                                   │       ├── ComparisonQuizGameResultEntity.kt
│   │                                   │       ├── MultiChoiceGameResultEntity.kt
│   │                                   │       └── WordleGameResultEntity.kt
│   │                                   └── util/
│   │                                       ├── converters/
│   │                                       │   ├── ListConverter.kt
│   │                                       │   ├── LocalDateConverter.kt
│   │                                       │   ├── MathFormulaConverter.kt
│   │                                       │   └── QuestionDifficultyConverter.kt
│   │                                       └── mappers/
│   │                                           └── MultiChoiceQuestionMapper.kt
│   ├── datastore/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── datastore/
│   │       │                           ├── PreferenceRequest.kt
│   │       │                           ├── common/
│   │       │                           │   ├── LocalUserCommon.kt
│   │       │                           │   ├── RecentCategoryDataStoreCommon.kt
│   │       │                           │   └── SettingsCommon.kt
│   │       │                           ├── di/
│   │       │                           │   ├── LocalUserDatastoreModule.kt
│   │       │                           │   ├── RecentCategoriesDatastoreModule.kt
│   │       │                           │   └── SettingsDataStoreModule.kt
│   │       │                           └── manager/
│   │       │                               ├── DataStoreManager.kt
│   │       │                               └── PreferencesDatastoreManager.kt
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── datastore/
│   │       │                           ├── common/
│   │       │                           │   ├── DataAnalyticsCommon.kt
│   │       │                           │   └── TranslationCommon.kt
│   │       │                           └── di/
│   │       │                               └── DataAnalyticsDatastoreModule.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── datastore/
│   │                                   └── manager/
│   │                                       └── PreferencesDatastoreManagerTest.kt
│   ├── proguard-rules.pro
│   ├── remote-config/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── remote_config/
│   │       │                           └── initializer/
│   │       │                               └── RemoteConfigInitializer.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   ├── kotlin/
│   │       │   │   └── com/
│   │       │   │       └── infinitepower/
│   │       │   │           └── newquiz/
│   │       │   │               └── core/
│   │       │   │                   └── remote_config/
│   │       │   │                       ├── LocalDefaultsRemoteConfig.kt
│   │       │   │                       ├── RemoteConfig.kt
│   │       │   │                       ├── RemoteConfigValue.kt
│   │       │   │                       └── RemoteConfigXmlParser.kt
│   │       │   └── res/
│   │       │       └── xml/
│   │       │           └── remote_config_defaults.xml
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── remote_config/
│   │       │                           ├── FirebaseRemoteConfigImpl.kt
│   │       │                           └── initializer/
│   │       │                               └── RemoteConfigInitializer.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── remote_config/
│   │                                   ├── LocalRemoteConfig.kt
│   │                                   └── RemoteConfigTest.kt
│   ├── src/
│   │   ├── androidTest/
│   │   │   ├── AndroidManifest.xml
│   │   │   └── java/
│   │   │       └── com/
│   │   │           └── infinitepower/
│   │   │               └── newquiz/
│   │   │                   └── core/
│   │   │                       └── ui/
│   │   │                           └── components/
│   │   │                               ├── RemainingTimeComponentTest.kt
│   │   │                               ├── category/
│   │   │                               │   ├── CategoryComponentTest.kt
│   │   │                               │   └── CategoryConnectionInfoBadgeTest.kt
│   │   │                               ├── icon/
│   │   │                               │   └── button/
│   │   │                               │       └── BackIconButtonTest.kt
│   │   │                               └── skip_question/
│   │   │                                   └── SkipQuestionDialogTest.kt
│   │   ├── main/
│   │   │   ├── AndroidManifest.xml
│   │   │   ├── java/
│   │   │   │   └── com/
│   │   │   │       └── infinitepower/
│   │   │   │           └── newquiz/
│   │   │   │               └── core/
│   │   │   │                   ├── NumberFormatter.kt
│   │   │   │                   ├── common/
│   │   │   │                   │   ├── BaseApiUrls.kt
│   │   │   │                   │   ├── Common.kt
│   │   │   │                   │   ├── compose/
│   │   │   │                   │   │   └── preview/
│   │   │   │                   │   │       └── BooleanPreviewParameterProvider.kt
│   │   │   │                   │   └── database/
│   │   │   │                   │       └── DatabaseCommon.kt
│   │   │   │                   ├── compose/
│   │   │   │                   │   └── preferences/
│   │   │   │                   │       └── LocalPreferenceEnabledStatus.kt
│   │   │   │                   ├── di/
│   │   │   │                   │   ├── KtorModule.kt
│   │   │   │                   │   └── NetworkStatusModule.kt
│   │   │   │                   ├── game/
│   │   │   │                   │   ├── ComparisonQuizCore.kt
│   │   │   │                   │   ├── GameCore.kt
│   │   │   │                   │   └── SkipGame.kt
│   │   │   │                   ├── math/
│   │   │   │                   │   └── evaluator/
│   │   │   │                   │       ├── Expressions.kt
│   │   │   │                   │       └── internal/
│   │   │   │                   │           ├── Evaluator.kt
│   │   │   │                   │           ├── Expr.kt
│   │   │   │                   │           ├── Function.kt
│   │   │   │                   │           ├── Parser.kt
│   │   │   │                   │           ├── Scanner.kt
│   │   │   │                   │           ├── Token.kt
│   │   │   │                   │           └── TokenType.kt
│   │   │   │                   ├── navigation/
│   │   │   │                   │   └── MazeNavigator.kt
│   │   │   │                   ├── network/
│   │   │   │                   │   ├── NetworkStatusTracker.kt
│   │   │   │                   │   └── NetworkStatusTrackerImpl.kt
│   │   │   │                   ├── theme/
│   │   │   │                   │   ├── ExtendedColor.kt
│   │   │   │                   │   ├── LocalAnimationsEnabled.kt
│   │   │   │                   │   ├── Spacing.kt
│   │   │   │                   │   ├── Theme.kt
│   │   │   │                   │   └── Type.kt
│   │   │   │                   ├── ui/
│   │   │   │                   │   ├── DisabledEmphasisWrappers.kt
│   │   │   │                   │   ├── ObserveAsEvents.kt
│   │   │   │                   │   ├── SnackbarController.kt
│   │   │   │                   │   ├── components/
│   │   │   │                   │   │   ├── AppNameWithLogo.kt
│   │   │   │                   │   │   ├── RemainingTimeComponent.kt
│   │   │   │                   │   │   ├── RoundedPolygonShape.kt
│   │   │   │                   │   │   ├── category/
│   │   │   │                   │   │   │   ├── CategoryBadge.kt
│   │   │   │                   │   │   │   └── CategoryComponent.kt
│   │   │   │                   │   │   ├── icon/
│   │   │   │                   │   │   │   └── button/
│   │   │   │                   │   │   │       └── BackIconButton.kt
│   │   │   │                   │   │   └── skip_question/
│   │   │   │                   │   │       ├── SkipButton.kt
│   │   │   │                   │   │       └── SkipQuestionDialog.kt
│   │   │   │                   │   ├── home/
│   │   │   │                   │   │   ├── ExpandCategoriesButton.kt
│   │   │   │                   │   │   ├── HomeCategoriesItems.kt
│   │   │   │                   │   │   └── HomeLazyColumn.kt
│   │   │   │                   │   ├── home_card/
│   │   │   │                   │   │   ├── HomeListContent.kt
│   │   │   │                   │   │   ├── components/
│   │   │   │                   │   │   │   ├── HomeCardIcon.kt
│   │   │   │                   │   │   │   ├── HomeCardItemContent.kt
│   │   │   │                   │   │   │   ├── HomeGroupTitle.kt
│   │   │   │                   │   │   │   ├── HomeHorizontalItems.kt
│   │   │   │                   │   │   │   ├── HomeLargeCard.kt
│   │   │   │                   │   │   │   ├── HomeMediumCard.kt
│   │   │   │                   │   │   │   └── PlayRandomQuizCard.kt
│   │   │   │                   │   │   └── model/
│   │   │   │                   │   │       └── HomeCardItem.kt
│   │   │   │                   │   ├── icons/
│   │   │   │                   │   │   └── TrophyIcon.kt
│   │   │   │                   │   └── text/
│   │   │   │                   │       └── CompactDecimalText.kt
│   │   │   │                   └── util/
│   │   │   │                       ├── ComposeUtils.kt
│   │   │   │                       ├── PackageUtils.kt
│   │   │   │                       ├── UiTextUtils.kt
│   │   │   │                       ├── UriUtils.kt
│   │   │   │                       ├── android/
│   │   │   │                       │   ├── DrawableUtils.kt
│   │   │   │                       │   └── resources/
│   │   │   │                       │       └── ResourcesUtil.kt
│   │   │   │                       ├── collections/
│   │   │   │                       │   └── Collections.kt
│   │   │   │                       ├── kotlin/
│   │   │   │                       │   ├── BooleanUtils.kt
│   │   │   │                       │   ├── CollectionsUtils.kt
│   │   │   │                       │   ├── Math.kt
│   │   │   │                       │   ├── NumberUtils.kt
│   │   │   │                       │   └── SetUtils.kt
│   │   │   │                       └── model/
│   │   │   │                           └── QuestionDifficultyUtil.kt
│   │   │   └── res/
│   │   │       ├── drawable/
│   │   │       │   ├── github_logo.xml
│   │   │       │   ├── logo_monochromatic.xml
│   │   │       │   ├── round_android_24.xml
│   │   │       │   └── round_flag_circle_24.xml
│   │   │       ├── mipmap-anydpi-v26/
│   │   │       │   ├── ic_launcher.xml
│   │   │       │   └── ic_launcher_round.xml
│   │   │       ├── raw/
│   │   │       │   ├── trophy2.json
│   │   │       │   ├── trophy_winner.json
│   │   │       │   ├── wordle_list.txt
│   │   │       │   ├── wordle_list_es.txt
│   │   │       │   ├── wordle_list_fr.txt
│   │   │       │   └── wordle_list_pt.txt
│   │   │       ├── values/
│   │   │       │   ├── ic_launcher_background.xml
│   │   │       │   ├── strings.xml
│   │   │       │   └── themes.xml
│   │   │       ├── values-de/
│   │   │       │   └── strings.xml
│   │   │       ├── values-es/
│   │   │       │   └── strings.xml
│   │   │       ├── values-et/
│   │   │       │   └── strings.xml
│   │   │       ├── values-fr/
│   │   │       │   └── strings.xml
│   │   │       ├── values-nb-rNO/
│   │   │       │   └── strings.xml
│   │   │       ├── values-night/
│   │   │       │   └── themes.xml
│   │   │       ├── values-pt/
│   │   │       │   └── strings.xml
│   │   │       ├── values-ta/
│   │   │       │   └── strings.xml
│   │   │       └── values-v29/
│   │   │           └── themes.xml
│   │   ├── normal/
│   │   │   ├── AndroidManifest.xml
│   │   │   └── kotlin/
│   │   │       └── com/
│   │   │           └── infinitepower/
│   │   │               └── newquiz/
│   │   │                   └── core/
│   │   │                       └── initializer/
│   │   │                           └── CoreFirebaseInitializer.kt
│   │   └── test/
│   │       └── java/
│   │           └── com/
│   │               └── infinitepower/
│   │                   └── newquiz/
│   │                       └── core/
│   │                           ├── NumberFormatterTest.kt
│   │                           ├── game/
│   │                           │   └── ComparisonQuizDataTest.kt
│   │                           └── util/
│   │                               ├── UiTextTests.kt
│   │                               ├── collections/
│   │                               │   └── CollectionsTest.kt
│   │                               └── kotlin/
│   │                                   ├── BooleanUtilsTest.kt
│   │                                   ├── CollectionsUtilsTest.kt
│   │                                   ├── MathTest.kt
│   │                                   ├── NumberUtilsTest.kt
│   │                                   └── SetUtilsTest.kt
│   ├── testing/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── testing/
│   │       │                           └── di/
│   │       │                               └── TestRemoteConfigModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── testing/
│   │       │                           ├── NewQuizTestRunner.kt
│   │       │                           ├── ScreenshotComparator.kt
│   │       │                           ├── data/
│   │       │                           │   ├── fake/
│   │       │                           │   │   ├── FakeComparisonQuizData.kt
│   │       │                           │   │   └── FakeData.kt
│   │       │                           │   └── repository/
│   │       │                           │       ├── comparison_quiz/
│   │       │                           │       │   └── FakeComparisonQuizRepositoryImpl.kt
│   │       │                           │       ├── multi_choice_quiz/
│   │       │                           │       │   └── TestMultiChoiceQuestionRepositoryImpl.kt
│   │       │                           │       └── numbers/
│   │       │                           │           └── FakeNumberTriviaQuestionApiImpl.kt
│   │       │                           ├── di/
│   │       │                           │   ├── TestDatabaseModule.kt
│   │       │                           │   ├── TestKtorModule.kt
│   │       │                           │   ├── TestRepositoryModule.kt
│   │       │                           │   └── WorkManagerModule.kt
│   │       │                           ├── domain/
│   │       │                           │   ├── FakeDailyChallengeDao.kt
│   │       │                           │   └── FakeGameResultDao.kt
│   │       │                           ├── ui/
│   │       │                           │   └── theme/
│   │       │                           │       └── TestTheme.kt
│   │       │                           └── utils/
│   │       │                               ├── ComposeRule.kt
│   │       │                               ├── LocaleUtils.kt
│   │       │                               └── LogUtils.kt
│   │       └── normal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── testing/
│   │                                   └── di/
│   │                                       ├── RemoteConfigModule.kt
│   │                                       └── TestAnalyticsModule.kt
│   ├── translation/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── androidTestNormal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── translation/
│   │       │                       └── GoogleTranslatorUtilTest.kt
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── NoTranslatorUtil.kt
│   │       │                           └── di/
│   │       │                               └── TranslatorModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── TranslatorLanguageSettings.kt
│   │       │                           ├── TranslatorModelState.kt
│   │       │                           └── TranslatorUtil.kt
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── GoogleTranslatorUtil.kt
│   │       │                           └── di/
│   │       │                               └── GoogleTranslatorModule.kt
│   │       ├── testFoss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           └── NoTranslatorUtilTest.kt
│   │       └── testNormal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── translation/
│   │                                   └── GoogleTranslatorUtilTest.kt
│   └── user-services/
│       ├── .gitignore
│       ├── build.gradle.kts
│       └── src/
│           ├── androidTest/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── core/
│           │                       └── user_services/
│           │                           └── LocalUserServiceImplTest.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── core/
│           │                       └── user_services/
│           │                           ├── DateTimeRangeFormatter.kt
│           │                           ├── GameResultTracker.kt
│           │                           ├── InsufficientDiamondsException.kt
│           │                           ├── LocalUserService.kt
│           │                           ├── LocalUserServiceImpl.kt
│           │                           ├── UserService.kt
│           │                           ├── XpManager.kt
│           │                           ├── data/
│           │                           │   └── xp/
│           │                           │       ├── ComparisonQuizXpGeneratorImpl.kt
│           │                           │       ├── MultiChoiceQuizXpGeneratorImpl.kt
│           │                           │       └── WordleXpGeneratorImpl.kt
│           │                           ├── di/
│           │                           │   ├── UserModule.kt
│           │                           │   └── XpGeneratorsModule.kt
│           │                           ├── domain/
│           │                           │   └── xp/
│           │                           │       ├── ComparisonQuizXpGenerator.kt
│           │                           │       ├── MultiChoiceQuizXpGenerator.kt
│           │                           │       ├── WordleXpGenerator.kt
│           │                           │       └── XpGenerator.kt
│           │                           ├── model/
│           │                           │   └── User.kt
│           │                           └── workers/
│           │                               └── MultiChoiceQuizEndGameWorker.kt
│           └── test/
│               └── kotlin/
│                   └── com/
│                       └── infinitepower/
│                           └── newquiz/
│                               └── core/
│                                   └── user_services/
│                                       ├── DateTimeRangeFormatterTest.kt
│                                       ├── LocalUserServiceImplUnitTest.kt
│                                       ├── data/
│                                       │   └── xp/
│                                       │       ├── ComparisonQuizXpGeneratorImplTest.kt
│                                       │       ├── MultiChoiceQuizXpGeneratorImplTest.kt
│                                       │       └── WordleXpGeneratorImplTest.kt
│                                       └── model/
│                                           └── UserTest.kt
├── data/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── data/
│       │                       ├── daily_challenge/
│       │                       │   └── DailyChallengeRepositoryImplTest.kt
│       │                       ├── repository/
│       │                       │   ├── comparison_quiz/
│       │                       │   │   └── ComparisonQuizRepositoryImplTest.kt
│       │                       │   └── country/
│       │                       │       └── CountryRepositoryImplTest.kt
│       │                       └── worker/
│       │                           ├── daily_challenge/
│       │                           │   └── VerifyDailyChallengeWorkerTest.kt
│       │                           └── maze/
│       │                               ├── CleanMazeQuizWorkerTest.kt
│       │                               └── GenerateMazeQuizWorkerTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── infinitepower/
│       │   │           └── newquiz/
│       │   │               └── data/
│       │   │                   ├── di/
│       │   │                   │   ├── MathModule.kt
│       │   │                   │   └── RepositoryModule.kt
│       │   │                   ├── local/
│       │   │                   │   ├── multi_choice_quiz/
│       │   │                   │   │   └── category/
│       │   │                   │   │       └── MultiChoiceQuestionCategories.kt
│       │   │                   │   └── wordle/
│       │   │                   │       └── WordleCategories.kt
│       │   │                   ├── repository/
│       │   │                   │   ├── UserConfigRepositoryImpl.kt
│       │   │                   │   ├── comparison_quiz/
│       │   │                   │   │   ├── ComparisonQuizApi.kt
│       │   │                   │   │   ├── ComparisonQuizApiImpl.kt
│       │   │                   │   │   └── ComparisonQuizRepositoryImpl.kt
│       │   │                   │   ├── country/
│       │   │                   │   │   ├── CountryEntity.kt
│       │   │                   │   │   └── CountryRepositoryImpl.kt
│       │   │                   │   ├── daily_challenge/
│       │   │                   │   │   ├── DailyChallengeRepositoryImpl.kt
│       │   │                   │   │   └── util/
│       │   │                   │   │       └── DailyChallengeTypeTitleUtil.kt
│       │   │                   │   ├── home/
│       │   │                   │   │   └── RecentCategoriesRepositoryImpl.kt
│       │   │                   │   ├── math_quiz/
│       │   │                   │   │   └── MathQuizCoreRepositoryImpl.kt
│       │   │                   │   ├── maze_quiz/
│       │   │                   │   │   └── MazeQuizRepositoryImpl.kt
│       │   │                   │   ├── multi_choice_quiz/
│       │   │                   │   │   ├── CountryCapitalFlagsQuizRepositoryImpl.kt
│       │   │                   │   │   ├── FlagQuizRepositoryImpl.kt
│       │   │                   │   │   ├── GuessMathSolutionRepositoryImpl.kt
│       │   │                   │   │   ├── LogoQuizRepositoryImpl.kt
│       │   │                   │   │   ├── MultiChoiceQuestionRepositoryImpl.kt
│       │   │                   │   │   ├── dto/
│       │   │                   │   │   │   └── OpenTDBQuestionResponse.kt
│       │   │                   │   │   └── saved_questions/
│       │   │                   │   │       └── SavedMultiChoiceQuestionsRepositoryImpl.kt
│       │   │                   │   ├── numbers/
│       │   │                   │   │   ├── NumberTriviaQuestionApiImpl.kt
│       │   │                   │   │   └── NumberTriviaQuestionRepositoryImpl.kt
│       │   │                   │   └── wordle/
│       │   │                   │       ├── InvalidWordError.kt
│       │   │                   │       └── WordleRepositoryImpl.kt
│       │   │                   ├── util/
│       │   │                   │   ├── mappers/
│       │   │                   │   │   ├── comparisonquiz/
│       │   │                   │   │   │   └── ComparisonQuizMapper.kt
│       │   │                   │   │   ├── daily_challenge/
│       │   │                   │   │   │   └── DailyChallengeTaskMapper.kt
│       │   │                   │   │   └── maze/
│       │   │                   │   │       └── MazeQuizMappers.kt
│       │   │                   │   └── translation/
│       │   │                   │       └── WordleTitleUtil.kt
│       │   │                   └── worker/
│       │   │                       ├── UpdateGlobalEventDataWorker.kt
│       │   │                       ├── daily_challenge/
│       │   │                       │   └── VerifyDailyChallengeWorker.kt
│       │   │                       ├── maze/
│       │   │                       │   ├── CleanMazeQuizWorker.kt
│       │   │                       │   └── GenerateMazeQuizWorker.kt
│       │   │                       └── multichoicequiz/
│       │   │                           └── DownloadMultiChoiceQuestionsWorker.kt
│       │   └── res/
│       │       └── raw/
│       │           └── all_countries.json
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── data/
│                               ├── local/
│                               │   ├── math_quiz/
│                               │   │   └── MathQuizCoreRepositoryImplTest.kt
│                               │   └── wordle/
│                               │       └── WordleCategoriesTest.kt
│                               └── repository/
│                                   ├── comparison_quiz/
│                                   │   ├── ComparisonQuizApiImplTest.kt
│                                   │   └── ComparisonQuizRepositoryImplTest.kt
│                                   ├── country/
│                                   │   ├── CountryRepositoryImplTest.kt
│                                   │   └── TestCountryRepositoryImpl.kt
│                                   ├── daily_challenge/
│                                   │   └── DailyChallengeRepositoryImplTest.kt
│                                   ├── home/
│                                   │   └── RecentCategoriesRepositoryImplTest.kt
│                                   ├── maze_quiz/
│                                   │   └── MazeQuizRepositoryImplTest.kt
│                                   ├── multi_choice_quiz/
│                                   │   ├── CountryCapitalFlagsQuizRepositoryImplTest.kt
│                                   │   └── FlagQuizRepositoryImplTest.kt
│                                   └── wordle/
│                                       └── WordleRepositoryImplTest.kt
├── detekt-compose.yml
├── detekt.yml
├── domain/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── domain/
│       │                       ├── repository/
│       │                       │   ├── CountryRepository.kt
│       │                       │   ├── UserConfigRepository.kt
│       │                       │   ├── comparison_quiz/
│       │                       │   │   └── ComparisonQuizRepository.kt
│       │                       │   ├── daily_challenge/
│       │                       │   │   └── DailyChallengeRepository.kt
│       │                       │   ├── home/
│       │                       │   │   └── RecentCategoriesRepository.kt
│       │                       │   ├── math_quiz/
│       │                       │   │   └── MathQuizCoreRepository.kt
│       │                       │   ├── maze/
│       │                       │   │   └── MazeQuizRepository.kt
│       │                       │   ├── multi_choice_quiz/
│       │                       │   │   ├── CountryCapitalFlagsQuizRepository.kt
│       │                       │   │   ├── FlagQuizRepository.kt
│       │                       │   │   ├── GuessMathSolutionRepository.kt
│       │                       │   │   ├── LogoQuizRepository.kt
│       │                       │   │   ├── MultiChoiceQuestionBaseRepository.kt
│       │                       │   │   ├── MultiChoiceQuestionRepository.kt
│       │                       │   │   └── saved_questions/
│       │                       │   │       └── SavedMultiChoiceQuestionsRepository.kt
│       │                       │   ├── numbers/
│       │                       │   │   ├── NumberTriviaQuestionApi.kt
│       │                       │   │   └── NumberTriviaQuestionRepository.kt
│       │                       │   └── wordle/
│       │                       │       └── WordleRepository.kt
│       │                       └── use_case/
│       │                           └── question/
│       │                               ├── GetRandomMultiChoiceQuestionUseCase.kt
│       │                               └── IsQuestionSavedUseCase.kt
│       └── test/
│           └── kotlin/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── domain/
│                               └── use_case/
│                                   └── question/
│                                       └── IsQuestionSavedUseCaseTest.kt
├── feature/
│   ├── daily-challenge/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── daily_challenge/
│   │                                   ├── DailyChallengeScreen.kt
│   │                                   ├── DailyChallengeScreenNavigator.kt
│   │                                   ├── DailyChallengeScreenUiEvent.kt
│   │                                   ├── DailyChallengeScreenUiState.kt
│   │                                   ├── DailyChallengeScreenViewModel.kt
│   │                                   └── components/
│   │                                       └── DailyChallengeCard.kt
│   ├── maze/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── feature/
│   │       │                       └── maze/
│   │       │                           ├── MazeScreen.kt
│   │       │                           ├── MazeScreenUiEvent.kt
│   │       │                           ├── MazeScreenUiState.kt
│   │       │                           ├── MazeScreenViewModel.kt
│   │       │                           ├── categories_info/
│   │       │                           │   ├── MazeCategoriesInfoScreen.kt
│   │       │                           │   ├── MazeCategoriesInfoUiState.kt
│   │       │                           │   └── MazeCategoriesInfoViewModel.kt
│   │       │                           ├── common/
│   │       │                           │   └── MazeCategories.kt
│   │       │                           ├── components/
│   │       │                           │   ├── CategoriesInfoBottomSheet.kt
│   │       │                           │   ├── InvalidCategoriesCard.kt
│   │       │                           │   ├── MazeCompletedCard.kt
│   │       │                           │   ├── MazeItemButton.kt
│   │       │                           │   ├── MazePath.kt
│   │       │                           │   └── ScrollToCurrentQuestionButton.kt
│   │       │                           ├── generate/
│   │       │                           │   ├── GenerateMazeScreen.kt
│   │       │                           │   ├── GenerateMazeScreenUiEvent.kt
│   │       │                           │   ├── GenerateMazeScreenUiState.kt
│   │       │                           │   └── GenerateMazeScreenViewModel.kt
│   │       │                           └── level_results/
│   │       │                               ├── LevelResultsScreen.kt
│   │       │                               ├── LevelResultsScreenUiState.kt
│   │       │                               ├── LevelResultsScreenViewModel.kt
│   │       │                               └── components/
│   │       │                                   ├── LevelCompletedContent.kt
│   │       │                                   └── LevelFailedContent.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── maze/
│   │                                   └── MazeScreenUiStateTest.kt
│   ├── profile/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── profile/
│   │                                   ├── ProfileScreen.kt
│   │                                   ├── ProfileScreenUiEvent.kt
│   │                                   ├── ProfileScreenUiState.kt
│   │                                   ├── ProfileViewModel.kt
│   │                                   └── components/
│   │                                       ├── GoodDayText.kt
│   │                                       ├── MainUserCard.kt
│   │                                       ├── UserXpAndLevelCard.kt
│   │                                       ├── XpEarnedByDayCard.kt
│   │                                       └── chart/
│   │                                           └── Marker.kt
│   └── settings/
│       ├── .gitignore
│       ├── README.md
│       ├── build.gradle.kts
│       └── src/
│           ├── foss/
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── feature/
│           │                       └── settings/
│           │                           ├── common/
│           │                           │   └── BuildVariant.kt
│           │                           └── screens/
│           │                               └── PreferencesScreen.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── feature/
│           │                       └── settings/
│           │                           ├── SettingsScreen.kt
│           │                           ├── components/
│           │                           │   ├── AboutAndHelpButtons.kt
│           │                           │   └── preferences/
│           │                           │       ├── PreferenceGroupHeader.kt
│           │                           │       ├── PreferenceItem.kt
│           │                           │       └── widgets/
│           │                           │           ├── CustomPreferenceWidget.kt
│           │                           │           ├── DropDownPreferenceWidget.kt
│           │                           │           ├── ListPreferenceWidget.kt
│           │                           │           ├── MultiSelectListPreferenceWidget.kt
│           │                           │           ├── NavigationButtonWidget.kt
│           │                           │           ├── SeekBarPreferenceWidget.kt
│           │                           │           ├── SwitchPreferenceWidget.kt
│           │                           │           └── TextPreferenceWidget.kt
│           │                           ├── model/
│           │                           │   ├── Preference.kt
│           │                           │   └── ScreenKey.kt
│           │                           ├── screens/
│           │                           │   ├── PreferenceScreen.kt
│           │                           │   ├── about_and_help/
│           │                           │   │   └── AboutAndHelpScreen.kt
│           │                           │   ├── animations/
│           │                           │   │   └── AnimationsScreen.kt
│           │                           │   ├── general/
│           │                           │   │   ├── GeneralScreen.kt
│           │                           │   │   ├── GeneralScreenUiEvent.kt
│           │                           │   │   ├── GeneralScreenUiState.kt
│           │                           │   │   └── GeneralScreenViewModel.kt
│           │                           │   ├── main/
│           │                           │   │   └── MainScreen.kt
│           │                           │   ├── multi_choice_quiz/
│           │                           │   │   └── MultiChoiceQuizScreen.kt
│           │                           │   └── wordle/
│           │                           │       └── WordleScreen.kt
│           │                           └── util/
│           │                               ├── ShowCategoryConnectionInfoUtils.kt
│           │                               └── datastore/
│           │                                   └── DatastoreUtils.kt
│           └── normal/
│               └── kotlin/
│                   └── com/
│                       └── infinitepower/
│                           └── newquiz/
│                               └── feature/
│                                   └── settings/
│                                       ├── common/
│                                       │   └── BuildVariant.kt
│                                       └── screens/
│                                           ├── PreferencesScreen.kt
│                                           ├── analytics/
│                                           │   └── AnimationsScreen.kt
│                                           └── translation/
│                                               ├── TranslationScreen.kt
│                                               ├── TranslationScreenUiEvent.kt
│                                               ├── TranslationScreenUiState.kt
│                                               └── TranslationScreenViewModel.kt
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lint.xml
├── model/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── model/
│       │                       ├── BaseCategory.kt
│       │                       ├── DataAnalyticsConsentState.kt
│       │                       ├── GameMode.kt
│       │                       ├── GameModeCategory.kt
│       │                       ├── Language.kt
│       │                       ├── NumberFormatType.kt
│       │                       ├── RemainingTime.kt
│       │                       ├── Resource.kt
│       │                       ├── TimestampWithValue.kt
│       │                       ├── UiText.kt
│       │                       ├── XP.kt
│       │                       ├── category/
│       │                       │   └── ShowCategoryConnectionInfo.kt
│       │                       ├── comparison_quiz/
│       │                       │   ├── ComparisonMode.kt
│       │                       │   ├── ComparisonQuizCategory.kt
│       │                       │   ├── ComparisonQuizCategoryEntity.kt
│       │                       │   ├── ComparisonQuizHelperValueState.kt
│       │                       │   ├── ComparisonQuizItem.kt
│       │                       │   ├── ComparisonQuizItemEntity.kt
│       │                       │   └── ComparisonQuizQuestion.kt
│       │                       ├── country/
│       │                       │   ├── Continent.kt
│       │                       │   └── Country.kt
│       │                       ├── daily_challenge/
│       │                       │   └── DailyChallengeTask.kt
│       │                       ├── global_event/
│       │                       │   └── GameEvent.kt
│       │                       ├── math_quiz/
│       │                       │   └── MathFormula.kt
│       │                       ├── maze/
│       │                       │   ├── MazePoint.kt
│       │                       │   └── MazeQuiz.kt
│       │                       ├── multi_choice_quiz/
│       │                       │   ├── MultiChoiceBaseCategory.kt
│       │                       │   ├── MultiChoiceCategory.kt
│       │                       │   ├── MultiChoiceQuestion.kt
│       │                       │   ├── MultiChoiceQuestionStep.kt
│       │                       │   ├── MultiChoiceQuestionType.kt
│       │                       │   ├── QuestionLanguage.kt
│       │                       │   ├── SelectedAnswer.kt
│       │                       │   ├── logo_quiz/
│       │                       │   │   └── LogoQuizBaseItem.kt
│       │                       │   └── saved/
│       │                       │       └── SortSavedQuestionsBy.kt
│       │                       ├── number/
│       │                       │   ├── NumberTriviaQuestion.kt
│       │                       │   └── NumberTriviaQuestionsEntity.kt
│       │                       ├── question/
│       │                       │   └── QuestionDifficulty.kt
│       │                       ├── regional_preferences/
│       │                       │   ├── DistanceUnitType.kt
│       │                       │   ├── RegionalPreferences.kt
│       │                       │   └── TemperatureUnit.kt
│       │                       ├── util/
│       │                       │   ├── base64/
│       │                       │   │   ├── Base64.kt
│       │                       │   │   ├── Base64Encoding.kt
│       │                       │   │   └── Base64Url.kt
│       │                       │   └── serializers/
│       │                       │       └── URISerializer.kt
│       │                       └── wordle/
│       │                           ├── WordleCategory.kt
│       │                           ├── WordleItem.kt
│       │                           ├── WordleQuizType.kt
│       │                           ├── WordleRowItem.kt
│       │                           └── WordleWord.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── model/
│                               ├── RemainingTimeTest.kt
│                               ├── category/
│                               │   └── ShowCategoryConnectionInfoTest.kt
│                               ├── comparison_quiz/
│                               │   ├── ComparisonQuizCategoryTest.kt
│                               │   └── ComparisonQuizQuestionTest.kt
│                               ├── daily_challenge/
│                               │   ├── DailyChallengeTaskTest.kt
│                               │   └── DailyChallengeTaskTypeTest.kt
│                               ├── math_quiz/
│                               │   └── maze/
│                               │       ├── MazePointTest.kt
│                               │       └── MazeQuizTest.kt
│                               ├── multi_choice_quiz/
│                               │   └── MultiChoiceQuestionTest.kt
│                               ├── util/
│                               │   └── base64/
│                               │       ├── Base64Test.kt
│                               │       └── Base64UrlTest.kt
│                               └── wordle/
│                                   ├── WordleItemTest.kt
│                                   └── WordleRowItemTest.kt
├── multi-choice-quiz/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── multi_choice_quiz/
│       │                       ├── MultiChoiceQuizScreenTest.kt
│       │                       └── components/
│       │                           ├── CardQuestionOptionTest.kt
│       │                           ├── QuizStepViewRowTest.kt
│       │                           └── QuizStepViewTest.kt
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── infinitepower/
│           │           └── newquiz/
│           │               └── multi_choice_quiz/
│           │                   ├── MultiChoiceQuizScreen.kt
│           │                   ├── MultiChoiceQuizScreenUiEvent.kt
│           │                   ├── MultiChoiceQuizScreenUiState.kt
│           │                   ├── MultiChoiceQuizScreenViewModel.kt
│           │                   ├── components/
│           │                   │   ├── CardQuestionAnswer.kt
│           │                   │   ├── MultiChoiceQuizContainer.kt
│           │                   │   ├── QuizStepView.kt
│           │                   │   ├── QuizTopBar.kt
│           │                   │   └── difficulty/
│           │                   │       ├── BaseCardDifficultyContent.kt
│           │                   │       ├── FilledCardDifficulty.kt
│           │                   │       ├── OutlinedCardDifficulty.kt
│           │                   │       └── SelectableDifficultyRow.kt
│           │                   ├── list/
│           │                   │   ├── MultiChoiceQuizListScreen.kt
│           │                   │   ├── MultiChoiceQuizListScreenUiState.kt
│           │                   │   └── MultiChoiceQuizListScreenViewModel.kt
│           │                   ├── results/
│           │                   │   └── MultiChoiceQuizResultsScreen.kt
│           │                   └── saved_questions/
│           │                       ├── SavedMultiChoiceQuestionsScreen.kt
│           │                       ├── SavedMultiChoiceQuestionsScreenNavigator.kt
│           │                       ├── SavedMultiChoiceQuestionsUiEvent.kt
│           │                       ├── SavedMultiChoiceQuestionsUiState.kt
│           │                       ├── SavedMultiChoiceQuestionsViewModel.kt
│           │                       └── components/
│           │                           └── SavedQuestionItem.kt
│           └── res/
│               └── values/
│                   └── strings.xml
├── settings.gradle.kts
└── wordle/
    ├── .gitignore
    ├── README.md
    ├── build.gradle.kts
    ├── consumer-rules.pro
    ├── proguard-rules.pro
    └── src/
        ├── androidTest/
        │   └── java/
        │       └── com/
        │           └── infinitepower/
        │               └── newquiz/
        │                   └── wordle/
        │                       ├── WordleScreenTest.kt
        │                       └── components/
        │                           ├── WordleKeyBoardTest.kt
        │                           └── WordleRowComponentTest.kt
        ├── main/
        │   ├── AndroidManifest.xml
        │   └── java/
        │       └── com/
        │           └── infinitepower/
        │               └── newquiz/
        │                   └── wordle/
        │                       ├── WordleScreen.kt
        │                       ├── WordleScreenUiEvent.kt
        │                       ├── WordleScreenUiState.kt
        │                       ├── WordleScreenViewModel.kt
        │                       ├── components/
        │                       │   ├── InfoDialog.kt
        │                       │   ├── WordleKeyBoard.kt
        │                       │   └── WordleRowComponent.kt
        │                       ├── list/
        │                       │   ├── WordleListScreen.kt
        │                       │   ├── WordleListScreenViewModel.kt
        │                       │   └── WordleListUiState.kt
        │                       └── util/
        │                           ├── InvalidWordErrorUiText.kt
        │                           ├── word/
        │                           │   └── WordUtil.kt
        │                           └── worker/
        │                               └── WordleEndGameWorker.kt
        └── test/
            └── java/
                └── com/
                    └── infinitepower/
                        └── newquiz/
                            └── wordle/
                                └── util/
                                    └── word/
                                        └── WordUtilTest.kt

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/actions/get-avd-info/action.yml
================================================
# From: coil-kt/coil
name: 'Get AVD Info'
description: 'Get the AVD info based on its API level.'
inputs:
  api-level:
    required: true
outputs:
  arch:
    value: ${{ steps.get-avd-arch.outputs.arch }}
  target:
    value: ${{ steps.get-avd-target.outputs.target }}
runs:
  using: "composite"
  steps:
    - id: get-avd-arch
      run: echo "::set-output name=arch::$(if [ ${{ inputs.api-level }} -ge 30 ]; then echo x86_64; else echo x86; fi)"
      shell: bash
    - id: get-avd-target
      run: echo "::set-output name=target::$(echo default)"
      shell: bash

================================================
FILE: .github/workflows/android.yml
================================================
name: Android CI

on:
  push:
    branches: [ "main" ]
    paths-ignore:
      - '**.md'
  pull_request:
    branches: [ "main" ]
    paths-ignore:
      - '**.md'

concurrency:
  group: android-ci-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read
  checks: write
  id-token: write

env:
  JAVA_VERSION: "17"
  JAVA_DISTR: 'zulu'

jobs:
  tests_and_apk:
    name: "🤖 Local Tests and 📦 APKs"
    runs-on: ubuntu-20.04

    timeout-minutes: 60

    steps:
      - name: Checkout sources
        uses: actions/checkout@v4

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@v3

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: ${{ env.JAVA_DISTR }}
          java-version: ${{ env.JAVA_VERSION }}

      - name: Create google-services.json file
        run: cat /home/runner/work/newquiz/newquiz/app/google-services.json | base64

      - name: Put google-services.json data
        env:
          DATA: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo $DATA > /home/runner/work/newquiz/newquiz/app/google-services.json

      - name: Workaround for Android Gradle Plugin issue
        run: 'echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" > local.properties'

      - name: Setup gradle
        uses: gradle/actions/setup-gradle@v3

      - name: Run unit tests
        run: ./gradlew testAllUnitTest --stacktrace

      - name: Publish Test Report
        uses: mikepenz/action-junit-report@v4
        if: success() || failure() # always run even if the previous step fails
        with:
          report_paths: '**/build/test-results/test*/TEST-*.xml'

      - name: Lint sources
        run: ./gradlew lint --stacktrace

      - name: Generate GitHub annotations
        uses: yutailang0119/action-android-lint@v4
        with:
          report-path: '**/build/reports/*.xml'

      - name: Run Detekt
        run: ./gradlew detekt --stacktrace

      - name: Assemble debug APKs
        run: ./gradlew assembleNormalDebug assembleFossDebug --stacktrace

      - name: Upload APKs
        uses: actions/upload-artifact@v4
        with:
          name: APKs
          path: app/build/outputs/apk/**/app-*-universal-debug.apk


================================================
FILE: .github/workflows/android_old.yml
================================================
name: Android CI

on:
  workflow_dispatch:

permissions:
  contents: read
  checks: write
  id-token: write

env:
  JAVA_VERSION: "17"
  JAVA_DISTR: 'corretto'

jobs:
  test:
    name: "🤖 Unit Tests"
    runs-on: ubuntu-20.04

    steps:
      - name: Checkout sources
        uses: actions/checkout@v3

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: ${{ env.JAVA_DISTR }}
          java-version: ${{ env.JAVA_VERSION }}

      - name: Create google-services.json file
        run: cat /home/runner/work/newquiz/newquiz/app/google-services.json | base64

      - name: Put google-services.json data
        env:
          DATA: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo $DATA > /home/runner/work/newquiz/newquiz/app/google-services.json

      - name: Workaround for Android Gradle Plugin issue
        run: 'echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" > local.properties'

      - name: Setup gradle
        uses: gradle/gradle-build-action@v2.5.1

      - name: Run tests
        run: ./gradlew testAllUnitTest --stacktrace
#        run: ./gradlew testNormalDebug testFossDebug --stacktrace

      - name: Publish Test Report
        uses: mikepenz/action-junit-report@v3
        if: success() || failure() # always run even if the previous step fails
        with:
          report_paths: '**/build/test-results/test*/TEST-*.xml'

  android-lint:
    name: "🔍 Android Lint"
    runs-on: ubuntu-latest

    steps:
      - name: Checkout sources
        uses: actions/checkout@v3

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: ${{ env.JAVA_DISTR }}
          java-version: ${{ env.JAVA_VERSION }}

      - name: Create google-services.json file
        run: cat /home/runner/work/newquiz/newquiz/app/google-services.json | base64

      - name: Put google-services.json data
        env:
          DATA: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo $DATA > /home/runner/work/newquiz/newquiz/app/google-services.json

      - name: Increase gradle daemon memory
        run: "echo \"org.gradle.jvmargs=-Xmx4096m\" >> gradle.properties"

      - name: Workaround for Android Gradle Plugin issue
        run: 'echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" > local.properties'

      - name: Setup gradle
        uses: gradle/gradle-build-action@v2.5.1

      - name: Lint sources
        run: ./gradlew lint --stacktrace

      - name: Generate GitHub annotations
        uses: yutailang0119/action-android-lint@v3
        with:
          report-path: '**/build/reports/*.xml'

  assemble-apk:
    name: "📦 Assemble APKs"
    needs:
      - test
      - android-lint
    runs-on: ubuntu-latest

    steps:
      - name: Checkout sources
        uses: actions/checkout@v3

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: ${{ env.JAVA_DISTR }}
          java-version: ${{ env.JAVA_VERSION }}

      - name: Create google-services.json file
        run: cat /home/runner/work/newquiz/newquiz/app/google-services.json | base64

      - name: Put google-services.json data
        env:
          DATA: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo $DATA > /home/runner/work/newquiz/newquiz/app/google-services.json

      - name: Workaround for Android Gradle Plugin issue
        run: 'echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" > local.properties'

      - name: Setup gradle
        uses: gradle/gradle-build-action@v2.5.1

      - name: Assemble debug APKs
        run: ./gradlew assembleNormalDebug assembleFossDebug --stacktrace

      - name: Upload APKs
        uses: actions/upload-artifact@v3
        with:
          name: APKs
          path: app/build/outputs/apk/**/app-*-universal-debug.apk
#                app/build/outputs/apk/debug/app-universal-debug.apk


================================================
FILE: .gitignore
================================================
.gradle
/local.properties
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

/app/build
/app/release

/buildSrc/build

# built application files
*.apk
*.ap_

# files for the dex VM
*.dex

# Java class files
*.class

# generated files
bin/
gen/
out/

# Eclipse project files
.classpath
.project

# IDEA/Android Studio project files, because
# the project can be imported from settings.gradle.kts
*.iml
.idea/*
!.idea/copyright
# Keep the code styles.
!/.idea/codeStyles
/.idea/codeStyles/*
!/.idea/codeStyles/Project.xml
!/.idea/codeStyles/codeStyleConfig.xml
!.idea/runConfigurations/

.kotlin


================================================
FILE: LICENCE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# New Quiz

[![Version](https://img.shields.io/badge/Version-1.6.2-blueviolet)](https://github.com/joaomanaia/newquiz/releases/tag/1.6.2)
[![Android CI](https://github.com/joaomanaia/newquiz/actions/workflows/android.yml/badge.svg?branch=main)](https://github.com/joaomanaia/newquiz/actions/workflows/android.yml)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
[![Translation status](https://hosted.weblate.org/widgets/newquiz/-/android-strings/svg-badge.svg)](https://hosted.weblate.org/engage/newquiz)

<a href='https://www.amazon.com/InfinitePower-NewQuiz/dp/B08T8JN4P9'><img height="75" alt='Available at amazon appstore' src='https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/devportal2/res/images/amazon-appstore-badge-english-black.png'/></a>

Do you like to challenge your knowledge? So NewQuiz is the ideal game for you.

![NewQuiz purple light](pictures/NewQuiz-Promotion-purple-light.png)

New quiz is optimized to material you, the theme of new quiz will adapt to your background.

![NewQuiz green night](pictures/NewQuiz-Promotion-green-night.png)

# Features

- Maze: Game mode with all other NewQuiz game modes in one quiz.

- Multi choice quiz
  - Logo quiz
  - Flag quiz
  - Solve the formula equation
  - Number trivia
  
- Wordle
  - Guess the text word
  - Guess the number
  - Guess the math formula
  - Number trivia
  
 - Comparison Quiz
   - Compare the country population 

# Build With

- [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) is an architectural pattern in computer software that facilitates the separation of the development of the graphical user interface

- [Jetpack Compose:](https://developer.android.com/jetpack/compose) Jetpack Compose is Android’s modern toolkit for building native UI.
- [Material 3:](https://m3.material.io/) Design and build beautiful, usable products with Material3.
- [Kotlin:](https://kotlinlang.org/) A modern programming language that makes developers happier.
- [Kotlin Coroutines:](https://github.com/Kotlin/kotlinx.coroutines) Asynchronous or non-blocking programming
- [Dagger Hilt:](https://github.com/google/dagger) A fast dependency injector for Java and Android.
- [Ktor:](https://ktor.io/) For asynchronous HTTP client requests.
- [Lottie Android:](https://github.com/airbnb/lottie-android/) Lottie is a library that parses Adobe After Effects animations exported as json.
- [Compose destinations:](https://github.com/raamcosta/compose-destinations) Annotation processing library for type-safe Jetpack Compose navigation with no boilerplate.

# Question Data Source

- [FlagCDN:](https://flagcdn.com/) country flag images

- Multi choice quiz
  - [OpenTDB:](https://opentdb.com/) multi choice questions
  - [NumbersAPI:](http://numbersapi.com) api for number trivia questions
- Wordle
  - [Spanish and French words](https://github.com/lorenbrichter/Words)
- Comparison Quiz
  - [Rest Countries:](https://restcountries.com/) country information
  - [TMDB:](https://www.themoviedb.org/) data about movies

# Translation

Hello and thank you for your interest — NewQuiz is being translated using [Weblate](https://weblate.org/), a web tool designed to ease translating for both developers and translators.

[![Translation status](https://hosted.weblate.org/widgets/newquiz/-/android-strings/horizontal-auto.svg)](https://hosted.weblate.org/engage/newquiz/)

# Run the project locally

## Requirements

- [Android Studio](https://developer.android.com/studio) Hedgehog 2023.1.1 Canary 16 or later. Or use an other version of [Android Studio](https://developer.android.com/studio) but you need to change the gradle version to be compatible with your version of [Android Studio](https://developer.android.com/studio).
  
- Java 17 or later.

## Build and Run

1. First clone the repository

```bash
git clone https://github.com/joaomanaia/newquiz.git
```

2. Open the project in [Android Studio](https://developer.android.com/studio).

3. Add firebase to the project

   1. Go to [Firebase](https://firebase.google.com/) and create a new project.
   2. Add an android app to the project.
   3. Download the google-services.json file.
   4. Copy the file to the app folder.

4. Click the run button.

> **Warning**: FOSS Builds still contains proprietary code, such as Firebase, Crashlytics, and Google Play Services. In the future all proprietary code will be removed from the FOSS Builds.

> **Warning**: To run the project locally you need to add firebase to the project, otherwise the you cannot build and run the project.


================================================
FILE: app/.gitignore
================================================
/build
google-services.json

*.apk
*.aab
*.dm
output-metadata.json

================================================
FILE: app/build.gradle.kts
================================================
plugins {
    alias(libs.plugins.newquiz.android.application)
    alias(libs.plugins.newquiz.android.application.compose)
    alias(libs.plugins.newquiz.android.hilt)
    alias(libs.plugins.newquiz.android.compose.destinations)
    alias(libs.plugins.newquiz.kotlin.serialization)
    id("kotlin-parcelize")
    id("com.google.android.gms.oss-licenses-plugin")
    alias(libs.plugins.newquiz.detekt)
}

android {
    namespace = "com.infinitepower.newquiz"
    compileSdk = 35

    defaultConfig {
        applicationId = "com.infinitepower.newquiz"
        minSdk = 21
        targetSdk = 35
        versionCode = 16
        versionName = "2.0.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true

        // resourceConfigurations += setOf("en", "pt", "fr", "es", "nb")
    }

    androidResources {
        generateLocaleConfig = true
    }

    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            isDebuggable = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }

        debug {
            extra["enableCrashlytics"] = false

            rootProject.ext.set("firebasePerformanceInstrumentationEnabled", "false")
        }
    }
    buildFeatures {
        compose = true
        buildConfig = true
    }

    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }

    splits {
        abi {
            isEnable = true
            reset()
            include("x86", "x86_64", "arm64-v8a", "armeabi-v7a")

            // Generate universal APK
            isUniversalApk = true
        }
    }
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.core.splashscreen)
    implementation(libs.androidx.appcompat)

    implementation(libs.androidx.activity.compose)
    implementation(libs.androidx.constraintlayout.compose)

    implementation(libs.androidx.lifecycle.livedata.ktx)
    implementation(libs.androidx.lifecycle.runtimeCompose)
    implementation(libs.androidx.lifecycle.viewModelCompose)

    implementation(libs.androidx.startup.runtime)

    implementation(libs.androidx.compose.ui)
    implementation(libs.androidx.compose.ui.tooling)
    implementation(libs.androidx.compose.material.iconsExtended)
    implementation(libs.androidx.compose.material3)
    implementation(libs.androidx.compose.material3.windowSizeClass)
    debugImplementation(libs.androidx.compose.ui.testManifest)
    androidTestImplementation(libs.androidx.compose.ui.test)

    implementation(libs.google.material)

    implementation(libs.hilt.navigationCompose)
    implementation(libs.hilt.ext.work)
    ksp(libs.hilt.ext.compiler)

    testImplementation(libs.kotlinx.coroutines.test)
    implementation(libs.kotlinx.coroutines.playServices)

    implementation(libs.lottie.compose)

    implementation(libs.ktor.client.core)
    implementation(libs.ktor.client.okhttp)
    implementation(libs.ktor.client.serialization)

    implementation(libs.androidx.work.ktx)
    androidTestImplementation(libs.androidx.work.testing)

    implementation(libs.kotlinx.datetime)

    implementation(libs.slf4j.simple)

    implementation(libs.google.oss.licenses)

    implementation(libs.kotlinx.collections.immutable)

    implementation(projects.core)
    implementation(projects.core.analytics)
    implementation(projects.core.datastore)
    implementation(projects.core.translation)
    implementation(projects.core.remoteConfig)
    implementation(projects.core.userServices)
    implementation(projects.feature.dailyChallenge)
    implementation(projects.feature.settings)
    implementation(projects.feature.maze)
    implementation(projects.feature.profile)
    implementation(projects.model)
    implementation(projects.multiChoiceQuiz)
    implementation(projects.wordle)
    implementation(projects.data)
    implementation(projects.domain)
    implementation(projects.comparisonQuiz)
}


================================================
FILE: app/lint-baseline.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 7.4.0-alpha09" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha09)" variant="fatal" version="7.4.0-alpha09">

</issues>


================================================
FILE: app/proguard-rules.pro
================================================
# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

-keepclassmembers @kotlinx.serialization.Serializable class ** {
    *** Companion;
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

-keep class kotlin.reflect.** { *; }
-dontwarn kotlin.reflect.**
-keep class org.jetbrains.** { *; }

# Firebase
-keep class com.google.firebase.** { *; }
-keep class com.firebase.** { *; }
-keep class org.apache.** { *; }
-keepnames class com.fasterxml.jackson.** { *; }
-keepnames class javax.servlet.** { *; }
-keepnames class org.ietf.jgss.** { *; }
-dontwarn org.w3c.dom.**
-dontwarn org.joda.time.**
-dontwarn org.shaded.apache.**
-dontwarn org.ietf.jgss.**
-keep class com.google.android.gms.** { *; }
-keep class org.apache** { *; }

# Only necessary if you downloaded the SDK jar directly instead of from maven.
-keep class com.shaded.fasterxml.jackson.** { *; }

-dontwarn java.lang.invoke.StringConcatFactory

-dontwarn kotlin.**
-dontwarn org.w3c.dom.events.*
-dontwarn org.jetbrains.kotlin.di.InjectorForRuntimeDescriptorLoader

-keepattributes SourceFile,LineNumberTable

-keep class kotlin.** { *; }
#-keep class kotlin.reflect.** { *; }
#-keep class org.jetbrains.kotlin.** { *; }

-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
    **[] $VALUES;
    public *;
}

-keepattributes InnerClasses

# Ktor
-keep class io.ktor.** { *; }
-keep class kotlinx.coroutines.** { *; }
-dontwarn kotlinx.atomicfu.**
-dontwarn io.netty.**
-dontwarn com.typesafe.**
-dontwarn org.slf4j.**

-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.SerializationKt
-keep,includedescriptorclasses class com.infinitepower.newsocial.compose.**$$serializer { *; }

-keep class kotlin.reflect.** { *; }
-dontwarn kotlin.reflect.**
-keep class org.jetbrains.** { *; }

-dontwarn kotlin.**
-dontwarn org.w3c.dom.events.*
-dontwarn org.jetbrains.kotlin.di.InjectorForRuntimeDescriptorLoader

-keepattributes SourceFile,LineNumberTable

-keep class kotlin.** { *; }
#-keep class kotlin.reflect.** { *; }
#-keep class org.jetbrains.kotlin.** { *; }

-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
    **[] $VALUES;
    public *;
}

-keepattributes InnerClasses

# Ktor
-keep class io.ktor.** { *; }
-keep class kotlinx.coroutines.** { *; }
-dontwarn kotlinx.atomicfu.**
-dontwarn io.netty.**
-dontwarn com.typesafe.**
-dontwarn org.slf4j.**

-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.SerializationKt
-keep,includedescriptorclasses class com.infinitepower.newsocial.compose.**$$serializer { *; }

-keep class kotlin.reflect.** { *; }
-dontwarn kotlin.reflect.**
-keep class org.jetbrains.** { *; }

-dontwarn java.lang.management.ManagementFactory
-dontwarn java.lang.management.RuntimeMXBean

================================================
FILE: app/src/androidTest/AndroidManifest.xml
================================================
<manifest
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:name=".NewQuizApp">
        <activity
            android:name="com.infinitepower.newquiz.ui.main.MainActivity"
            android:exported="true"
            android:hardwareAccelerated="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="remove" />

        <!-- disable firebase provider to get rid of "Default FirebaseApp is not initialized in this process" exceptions -->
        <provider
            android:authorities="${applicationId}.firebaseperfprovider"
            android:name="com.google.firebase.perf.provider.FirebasePerfProvider"
            tools:node="remove" />

        <meta-data
            android:name="firebase_performance_collection_deactivated"
            android:value="true" />

        <meta-data
            android:name="firebase_crashlytics_collection_enabled"
            android:value="false" />
    </application>
</manifest>

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.infinitepower.newquiz">

    <dist:module dist:instant="true" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:name=".NewQuizApp"
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:appCategory="game"
        android:isGame="true"
        android:theme="@style/Theme.NewQuiz.Starting"
        tools:ignore="UnusedAttribute"
        android:enableOnBackInvokedCallback="true">
        <activity
            android:name="com.infinitepower.newquiz.ui.main.MainActivity"
            android:exported="true"
            android:hardwareAccelerated="true"
            android:theme="@style/Theme.NewQuiz.Starting">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.shortcuts"
                android:resource="@xml/shortcuts" />
        </activity>

        <activity
            android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
            android:theme="@style/Theme.NewQuiz" />

        <activity
            android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
            android:theme="@style/Theme.NewQuiz" />

        <meta-data
            android:name="firebase_performance_logcat_enabled"
            android:value="true" />

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">
            <meta-data
                android:name="androidx.work.WorkManagerInitializer"
                android:value="androidx.startup"
                tools:node="remove" />

            <!-- WorkManager Initializer-->
            <meta-data
                android:name="com.infinitepower.newquiz.initializer.WorkManagerInitializer"
                android:value="androidx.startup" />

            <meta-data
                android:name="com.infinitepower.newquiz.initializer.EnqueueStartWorksInitializer"
                android:value="androidx.startup" />
        </provider>

        <!-- Turn off firebase analytics automatically data collection -->
        <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />

        <!-- Turn off firebase crashlytics automatically data collection -->
        <meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />

        <!-- Turn off firebase performance automatically data collection -->
        <meta-data android:name="firebase_performance_collection_enabled" android:value="false" />
    </application>
</manifest>


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/NewQuizApp.kt
================================================
package com.infinitepower.newquiz

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class NewQuizApp : Application()


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/core/navigation/AppNavGraphs.kt
================================================
package com.infinitepower.newquiz.core.navigation

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import com.infinitepower.newquiz.comparison_quiz.destinations.ComparisonQuizListScreenDestination
import com.infinitepower.newquiz.comparison_quiz.destinations.ComparisonQuizScreenDestination
import com.infinitepower.newquiz.core.remote_config.RemoteConfig
import com.infinitepower.newquiz.feature.daily_challenge.destinations.DailyChallengeScreenDestination
import com.infinitepower.newquiz.feature.maze.destinations.LevelResultsScreenDestination
import com.infinitepower.newquiz.feature.maze.destinations.MazeCategoriesInfoScreenDestination
import com.infinitepower.newquiz.feature.maze.destinations.MazeScreenDestination
import com.infinitepower.newquiz.feature.profile.destinations.ProfileScreenDestination
import com.infinitepower.newquiz.feature.settings.destinations.SettingsScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizListScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizResultsScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.destinations.SavedMultiChoiceQuestionsScreenDestination
import com.infinitepower.newquiz.ui.navigation.NavigationContainer
import com.infinitepower.newquiz.wordle.destinations.WordleListScreenDestination
import com.infinitepower.newquiz.wordle.destinations.WordleScreenDestination
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
import com.ramcosta.composedestinations.navigation.dependency
import com.ramcosta.composedestinations.rememberNavHostEngine
import com.ramcosta.composedestinations.scope.DestinationScopeWithNoDependencies
import com.ramcosta.composedestinations.spec.DestinationSpec
import com.ramcosta.composedestinations.spec.NavGraphSpec
import com.ramcosta.composedestinations.spec.Route

@Immutable
internal data class NavGraph(
    override val route: String,
    override val startRoute: Route,
    val destinations: List<DestinationSpec<out Any>>,
    override val nestedNavGraphs: List<NavGraph> = emptyList()
) : NavGraphSpec {
    override val destinationsByRoute: Map<String, DestinationSpec<out Any>> =
        destinations.associateBy { it.route }
}

internal object AppNavGraphs {
    val mainNavGraph = NavGraph(
        route = "main_nav_graph",
        startRoute = MultiChoiceQuizListScreenDestination,
        destinations = listOf(
            MultiChoiceQuizScreenDestination,
            MultiChoiceQuizListScreenDestination,
            MultiChoiceQuizResultsScreenDestination,
            SettingsScreenDestination,
            SavedMultiChoiceQuestionsScreenDestination,
            WordleScreenDestination,
            WordleListScreenDestination,
            MazeScreenDestination,
            MazeCategoriesInfoScreenDestination,
            LevelResultsScreenDestination,
            ComparisonQuizScreenDestination,
            ComparisonQuizListScreenDestination,
            DailyChallengeScreenDestination,
            ProfileScreenDestination
        )
    )
}

internal fun DestinationScopeWithNoDependencies<*>.currentNavigator(
    remoteConfig: RemoteConfig
): CommonNavGraphNavigator {
    return CommonNavGraphNavigator(destinationsNavigator, navController, remoteConfig)
}

@Composable
@ExperimentalMaterial3Api
internal fun AppNavigation(
    modifier: Modifier = Modifier,
    navController: NavHostController,
    windowSizeClass: WindowSizeClass,
    remoteConfig: RemoteConfig,
    dailyChallengeClaimCount: Int,
    userDiamonds: UInt
) {
    NavigationContainer(
        navController = navController,
        windowWidthSize = windowSizeClass.widthSizeClass,
        dailyChallengeClaimCount = dailyChallengeClaimCount,
        userDiamonds = userDiamonds
    ) { innerPadding ->
        DestinationsNavHost(
            navGraph = AppNavGraphs.mainNavGraph,
            navController = navController,
            modifier = modifier.padding(innerPadding),
            dependenciesContainerBuilder = {
                dependency(currentNavigator(remoteConfig))
                dependency(windowSizeClass)
            },
            engine = rememberNavHostEngine(
                rootDefaultAnimations = RootNavGraphDefaultAnimations.ACCOMPANIST_FADING,
            )
        )
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/core/navigation/CommonNavGraphNavigator.kt
================================================
package com.infinitepower.newquiz.core.navigation

import androidx.navigation.NavController
import com.infinitepower.newquiz.comparison_quiz.destinations.ComparisonQuizScreenDestination
import com.infinitepower.newquiz.core.remote_config.RemoteConfig
import com.infinitepower.newquiz.core.remote_config.RemoteConfigValue
import com.infinitepower.newquiz.core.remote_config.get
import com.infinitepower.newquiz.data.util.mappers.comparisonquiz.toEntity
import com.infinitepower.newquiz.feature.daily_challenge.DailyChallengeScreenNavigator
import com.infinitepower.newquiz.feature.maze.destinations.LevelResultsScreenDestination
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizCategory
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizItem
import com.infinitepower.newquiz.model.maze.MazeQuiz
import com.infinitepower.newquiz.model.multi_choice_quiz.MultiChoiceBaseCategory
import com.infinitepower.newquiz.model.multi_choice_quiz.MultiChoiceQuestion
import com.infinitepower.newquiz.model.wordle.WordleQuizType
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.saved_questions.SavedQuestionsScreenNavigator
import com.infinitepower.newquiz.wordle.destinations.WordleScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.utils.destination

class CommonNavGraphNavigator(
    private val navigator: DestinationsNavigator,
    private val navController: NavController,
    private val remoteConfig: RemoteConfig
) : SavedQuestionsScreenNavigator,
    MazeNavigator,
    DailyChallengeScreenNavigator {

    override fun navigateToWordleQuiz(type: WordleQuizType) {
        navigator.navigate(WordleScreenDestination(quizType = type))
    }

    override fun navigateToComparisonQuiz(
        category: ComparisonQuizCategory,
        mode: ComparisonMode
    ) {
        navigator.navigate(ComparisonQuizScreenDestination(category.id, mode))
    }

    override fun navigateToMultiChoiceQuiz(initialQuestions: ArrayList<MultiChoiceQuestion>) {
        val remoteConfigDifficulty = remoteConfig
            .get(RemoteConfigValue.MULTICHOICE_QUICKQUIZ_DIFFICULTY)
            .run {
                if (this == "random") null else this
            }

        navigator.navigate(
            MultiChoiceQuizScreenDestination(
                initialQuestions = initialQuestions,
                difficulty = remoteConfigDifficulty
            )
        )
    }

    override fun navigateToMultiChoiceQuiz(category: MultiChoiceBaseCategory) {
        val remoteConfigDifficulty = remoteConfig
            .get(RemoteConfigValue.MULTICHOICE_QUICKQUIZ_DIFFICULTY)
            .run {
                if (this == "random") null else this
            }

        navigator.navigate(
            MultiChoiceQuizScreenDestination(
                difficulty = remoteConfigDifficulty,
                category = category
            )
        )
    }

    override fun navigateToGame(item: MazeQuiz.MazeItem) {
        val destination = when (item) {
            is MazeQuiz.MazeItem.Wordle -> {
                WordleScreenDestination(
                    word = item.wordleWord.word,
                    quizType = item.wordleQuizType,
                    mazeItemId = item.id.toString(),
                    textHelper = item.wordleWord.textHelper
                )
            }

            is MazeQuiz.MazeItem.MultiChoice -> {
                MultiChoiceQuizScreenDestination(
                    initialQuestions = arrayListOf(item.question),
                    mazeItemId = item.id.toString()
                )
            }

            is MazeQuiz.MazeItem.ComparisonQuiz -> {
                val initialItems = item.question.questions
                    .toList()
                    .map(ComparisonQuizItem::toEntity)

                ComparisonQuizScreenDestination(
                    categoryId = item.question.categoryId,
                    initialItems = ArrayList(initialItems),
                    mazeItemId = item.id
                )
            }
        }

        navigator.navigate(destination) {
            popUpTo(LevelResultsScreenDestination) {
                inclusive = true
            }
        }
    }

    override fun navigateToMazeResults(itemId: Int) {
        navigator.navigate(LevelResultsScreenDestination(itemId)) {
            launchSingleTop = true

            // Remove current screen from back stack
            val currentDestination = navController.currentBackStackEntry?.destination()
            if (currentDestination != null) {
                popUpTo(currentDestination) {
                    inclusive = true
                }
            }
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/core/navigation/NavigationItem.kt
================================================
package com.infinitepower.newquiz.core.navigation

import androidx.annotation.Keep
import androidx.annotation.StringRes
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.vector.ImageVector
import com.ramcosta.composedestinations.spec.Direction

sealed class NavigationItem {
    @get:StringRes
    abstract val text: Int

    abstract val group: NavDrawerItemGroup?

    @Immutable
    data class Label(
        @StringRes override val text: Int,
        override val group: NavDrawerItemGroup? = null
    ) : NavigationItem()

    /**
     * @param primary items to navigation bar
     */
    @Immutable
    data class Item(
        @StringRes override val text: Int,
        override val group: NavDrawerItemGroup? = null,
        val selectedIcon: ImageVector,
        val unselectedIcon: ImageVector? = null,
        val badge: NavDrawerBadgeItem? = null,
        val direction: Direction,
        val primary: Boolean = false,
        val screenType: ScreenType = ScreenType.NORMAL
    ) : NavigationItem() {
        fun getIcon(selected: Boolean): ImageVector {
            return if (selected || unselectedIcon == null) selectedIcon else unselectedIcon
        }
    }
}

enum class ScreenType {
    /** When using this type navigation items will be visible and have a top bar */
    NORMAL,

    /** When using this type all navigation items will be invisible and have no top bar */
    NAVIGATION_HIDDEN
}

@JvmInline
value class NavDrawerItemGroup(val key: String)

@Keep
data class NavDrawerBadgeItem(
    val value: Int,
    val description: String
)


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/core/workers/AppStartLoggingAnalyticsWorker.kt
================================================
package com.infinitepower.newquiz.core.workers

import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.infinitepower.newquiz.core.analytics.AnalyticsHelper
import com.infinitepower.newquiz.core.analytics.UserProperty
import com.infinitepower.newquiz.core.datastore.common.SettingsCommon
import com.infinitepower.newquiz.core.datastore.manager.DataStoreManager
import com.infinitepower.newquiz.core.datastore.di.SettingsDataStoreManager
import com.infinitepower.newquiz.core.translation.TranslatorUtil
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject

@HiltWorker
class AppStartLoggingAnalyticsWorker @AssistedInject constructor(
    @Assisted appContext: Context,
    @Assisted workerParams: WorkerParameters,
    @SettingsDataStoreManager private val settingsDataStoreManager: DataStoreManager,
    private val translatorUtil: TranslatorUtil,
    private val analyticsHelper: AnalyticsHelper
) : CoroutineWorker(appContext, workerParams) {
    companion object {
        fun enqueue(workManager: WorkManager) {
            val appStartLoggingAnalyticsWorker = OneTimeWorkRequestBuilder<AppStartLoggingAnalyticsWorker>().build()
            workManager.enqueue(appStartLoggingAnalyticsWorker)
        }
    }

    override suspend fun doWork(): Result {
        val wordleLang = settingsDataStoreManager.getPreference(SettingsCommon.InfiniteWordleQuizLanguage)
        analyticsHelper.setUserProperty(UserProperty.WordleLanguage(wordleLang))

        val isTranslatorModelDownloaded = translatorUtil.isModelDownloaded()
        analyticsHelper.setUserProperty(UserProperty.TranslatorModelDownloaded(isTranslatorModelDownloaded))

        return Result.success()
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/initializer/EnqueueStartWorksInitializer.kt
================================================
package com.infinitepower.newquiz.initializer

import android.content.Context
import androidx.startup.Initializer
import androidx.work.WorkManager
import com.infinitepower.newquiz.core.remote_config.initializer.RemoteConfigInitializer
import com.infinitepower.newquiz.core.workers.AppStartLoggingAnalyticsWorker
import com.infinitepower.newquiz.data.worker.daily_challenge.VerifyDailyChallengeWorker

@Suppress("unused")
class EnqueueStartWorksInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        val workManager = WorkManager.getInstance(context)

        VerifyDailyChallengeWorker.enqueueUniquePeriodicWork(workManager)
        AppStartLoggingAnalyticsWorker.enqueue(workManager)
    }

    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
        WorkManagerInitializer::class.java,
        RemoteConfigInitializer::class.java
    )
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/initializer/WorkManagerInitializer.kt
================================================
package com.infinitepower.newquiz.initializer

import android.content.Context
import android.util.Log
import androidx.hilt.work.HiltWorkerFactory
import androidx.startup.Initializer
import androidx.work.Configuration
import androidx.work.WorkManager
import dagger.Module
import dagger.Provides
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class WorkManagerInitializer : Initializer<WorkManager> {
    @Provides
    @Singleton
    override fun create(@ApplicationContext context: Context): WorkManager {
        if (!WorkManager.isInitialized()) {
            val entryPoint = EntryPointAccessors.fromApplication<WorkManagerInitializerEntryPoint>(context)

            val configuration = Configuration
                .Builder()
                .setWorkerFactory(entryPoint.hiltWorkerFactory())
                .setMinimumLoggingLevel(Log.INFO)
                .build()

            WorkManager.initialize(context, configuration)
        }

        return WorkManager.getInstance(context)
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }

    @EntryPoint
    @InstallIn(SingletonComponent::class)
    interface WorkManagerInitializerEntryPoint {
        fun hiltWorkerFactory(): HiltWorkerFactory
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/components/DataCollectionConsentDialog.kt
================================================
package com.infinitepower.newquiz.ui.components

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.core.theme.spacing
import com.infinitepower.newquiz.core.R as CoreR

@Composable
@ExperimentalMaterial3Api
internal fun DataCollectionConsentDialog(
    onAgreeClick: () -> Unit = {},
    onDisagreeClick: () -> Unit = {}
) {
    AlertDialog(
        title = { Text(text = stringResource(id = CoreR.string.data_collection_consent)) },
        text = {
            DialogConsentContent(
                onAgreeClick = onAgreeClick,
                onDisagreeClick = onDisagreeClick
            )
        },
        onDismissRequest = {},
        confirmButton = {},
        properties = DialogProperties(
            dismissOnBackPress = false,
            dismissOnClickOutside = false
        )
    )
}

@Composable
private fun DialogConsentContent(
    modifier: Modifier = Modifier,
    onAgreeClick: () -> Unit = {},
    onDisagreeClick: () -> Unit = {}
) {
    val spaceLarge = MaterialTheme.spacing.large

    val scrollState = rememberScrollState()

    Column(
        modifier = modifier.height(400.dp)
    ) {
        Text(
            text = stringResource(id = CoreR.string.data_collection_consent_description),
            style = MaterialTheme.typography.bodyLarge,
            modifier = Modifier
                .weight(1f)
                .verticalScroll(scrollState)
        )
        Spacer(modifier = Modifier.height(spaceLarge))
        ConsentButtons(
            onAgreeClick = onAgreeClick,
            onDisagreeClick = onDisagreeClick
        )
    }
}

@Composable
private fun ConsentButtons(
    modifier: Modifier = Modifier,
    onAgreeClick: () -> Unit = {},
    onDisagreeClick: () -> Unit = {}
) {
    Column(
        modifier = modifier.fillMaxWidth()
    ) {
        ConsentButton(
            text = stringResource(id = CoreR.string.data_collection_consent_agree),
            onClick = onAgreeClick,
            shape = RoundedCornerShape(
                topStart = 16.dp,
                topEnd = 16.dp,
                bottomStart = 8.dp,
                bottomEnd = 8.dp
            )
        )
        Spacer(modifier = Modifier.height(MaterialTheme.spacing.small))
        ConsentButton(
            text = stringResource(id = CoreR.string.data_collection_consent_disagree),
            onClick = onDisagreeClick,
            shape = RoundedCornerShape(
                topStart = 8.dp,
                topEnd = 8.dp,
                bottomStart = 16.dp,
                bottomEnd = 16.dp
            )
        )
    }
}

@Composable
private fun ConsentButton(
    text: String,
    shape: Shape = MaterialTheme.shapes.medium,
    onClick: () -> Unit
) {
    val buttonColor = if (isSystemInDarkTheme()) {
        MaterialTheme.colorScheme.primary
    } else {
        MaterialTheme.colorScheme.primaryContainer
    }

    Surface(
        onClick = onClick,
        color = buttonColor,
        shape = shape,
        modifier = Modifier.fillMaxWidth()
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Center
        ) {
            Text(
                modifier = Modifier.padding(20.dp),
                text = text,
                style = MaterialTheme.typography.titleMedium
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
@PreviewLightDark
private fun AnalyticsCollectionConsentContentPreview() {
    NewQuizTheme {
        Surface {
            DataCollectionConsentDialog()
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/components/DiamondsCounter.kt
================================================
package com.infinitepower.newquiz.ui.components

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.core.theme.spacing

@Composable
internal fun DiamondsCounter(
    modifier: Modifier = Modifier,
    diamonds: UInt
) {
    Surface(
        modifier = modifier,
        shape = MaterialTheme.shapes.small,
        color = MaterialTheme.colorScheme.surface,
        tonalElevation = 4.dp
    ) {
        Text(
            text = "$diamonds \uD83D\uDC8E",
            modifier = Modifier.padding(
                horizontal = MaterialTheme.spacing.small,
                vertical = MaterialTheme.spacing.extraSmall
            ),
        )
    }
}

@Composable
@PreviewLightDark
private fun DiamondsCounterPreview() {
    NewQuizTheme {
        Surface {
            DiamondsCounter(
                modifier = Modifier.padding(16.dp),
                diamonds = 100u
            )
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/main/MainActivity.kt
================================================
package com.infinitepower.newquiz.ui.main

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.compose.rememberNavController
import com.infinitepower.newquiz.core.analytics.AnalyticsHelper
import com.infinitepower.newquiz.core.analytics.LocalAnalyticsHelper
import com.infinitepower.newquiz.core.navigation.AppNavigation
import com.infinitepower.newquiz.core.remote_config.RemoteConfig
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.ui.components.DataCollectionConsentDialog
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class, ExperimentalMaterial3Api::class)
class MainActivity : ComponentActivity() {
    @Inject
    lateinit var analyticsHelper: AnalyticsHelper

    @Inject
    lateinit var remoteConfig: RemoteConfig

    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        val splashScreen = installSplashScreen()
        super.onCreate(savedInstanceState)

        var uiState: MainScreenUiState by mutableStateOf(MainScreenUiState())

        // Update the uiState
        lifecycleScope.launch {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState
                    .onEach { uiState = it }
                    .collect()
            }
        }

        // Keep the splash screen until the uiState is loaded
        splashScreen.setKeepOnScreenCondition { uiState.loading }

        enableEdgeToEdge()

        setContent {
            CompositionLocalProvider(
                LocalAnalyticsHelper provides analyticsHelper
            ) {
                NewQuizTheme(
                    animationsEnabled = uiState.animationsEnabled,
                ) {
                    val windowSize = calculateWindowSizeClass(activity = this)

                    Surface(
                        color = MaterialTheme.colorScheme.background
                    ) {
                        AppNavigation(
                            navController = rememberNavController(),
                            modifier = Modifier.fillMaxSize(),
                            windowSizeClass = windowSize,
                            remoteConfig = remoteConfig,
                            dailyChallengeClaimCount = uiState.dailyChallengeClaimableCount,
                            userDiamonds = uiState.userDiamonds,
                        )

                        if (uiState.showDataAnalyticsConsentDialog && !uiState.loading) {
                            DataCollectionConsentDialog(
                                onAgreeClick = {
                                    viewModel.onEvent(
                                        MainScreenUiEvent.OnDataAnalyticsConsentClick(
                                            agreed = true
                                        )
                                    )
                                },
                                onDisagreeClick = {
                                    viewModel.onEvent(
                                        MainScreenUiEvent.OnDataAnalyticsConsentClick(
                                            agreed = false
                                        )
                                    )
                                }
                            )
                        }
                    }
                }
            }
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/main/MainScreenUiEvent.kt
================================================
package com.infinitepower.newquiz.ui.main

import androidx.annotation.Keep

sealed interface MainScreenUiEvent {
    @Keep
    data class OnDataAnalyticsConsentClick(
        val agreed: Boolean
    ) : MainScreenUiEvent
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/main/MainScreenUiState.kt
================================================
package com.infinitepower.newquiz.ui.main

import androidx.annotation.Keep
import com.infinitepower.newquiz.core.theme.AnimationsEnabled

/**
 * Represents the state of the main screen.
 *
 * @param loading True if the main screen state is loading. The splash screen will be shown until this is false.
 */
@Keep
data class MainScreenUiState(
    val loading: Boolean = true,
    val showDataAnalyticsConsentDialog: Boolean = false,
    val dailyChallengeClaimableCount: Int = 0,
    val animationsEnabled: AnimationsEnabled = AnimationsEnabled(),
    val userDiamonds: UInt = 0u
)


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/main/MainViewModel.kt
================================================
package com.infinitepower.newquiz.ui.main

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.infinitepower.newquiz.core.analytics.AnalyticsHelper
import com.infinitepower.newquiz.core.datastore.common.SettingsCommon
import com.infinitepower.newquiz.core.datastore.di.SettingsDataStoreManager
import com.infinitepower.newquiz.core.datastore.manager.DataStoreManager
import com.infinitepower.newquiz.core.theme.AnimationsEnabled
import com.infinitepower.newquiz.core.user_services.UserService
import com.infinitepower.newquiz.domain.repository.daily_challenge.DailyChallengeRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(
    dailyChallengeRepository: DailyChallengeRepository,
    @SettingsDataStoreManager private val settingsDataStoreManager: DataStoreManager,
    private val analyticsHelper: AnalyticsHelper,
    private val userService: UserService
) : ViewModel() {
    private val animationsEnabledFlow = combine(
        settingsDataStoreManager.getPreferenceFlow(SettingsCommon.GlobalAnimationsEnabled),
        settingsDataStoreManager.getPreferenceFlow(SettingsCommon.WordleAnimationsEnabled),
        settingsDataStoreManager.getPreferenceFlow(SettingsCommon.MultiChoiceAnimationsEnabled),
    ) { globalAnimationsEnabled, wordleAnimationsEnabled, multiChoiceAnimationsEnabled ->
        AnimationsEnabled(
            global = globalAnimationsEnabled,
            wordle = wordleAnimationsEnabled && globalAnimationsEnabled,
            multiChoice = multiChoiceAnimationsEnabled && globalAnimationsEnabled
        )
    }

    val uiState: StateFlow<MainScreenUiState> = combine(
        animationsEnabledFlow,
        analyticsHelper.showDataAnalyticsConsentDialog,
        dailyChallengeRepository.getClaimableTasksCountFlow(),
        userService.getUserDiamondsFlow()
    ) { animationsEnabled, showDataAnalyticsConsentDialog, dailyChallengeClaimableCount, userDiamonds ->
        MainScreenUiState(
            loading = false,
            animationsEnabled = animationsEnabled,
            showDataAnalyticsConsentDialog = showDataAnalyticsConsentDialog,
            dailyChallengeClaimableCount = dailyChallengeClaimableCount,
            userDiamonds = userDiamonds
        )
    }.stateIn(
        scope = viewModelScope,
        initialValue = MainScreenUiState(),
        started = SharingStarted.WhileSubscribed(UI_STATE_STOP_TIMEOUT)
    )

    companion object {
        private const val UI_STATE_STOP_TIMEOUT = 5_000L
    }

    fun onEvent(event: MainScreenUiEvent) {
        when (event) {
            is MainScreenUiEvent.OnDataAnalyticsConsentClick -> viewModelScope.launch(Dispatchers.IO) {
                analyticsHelper.updateDataConsent(event.agreed)
            }
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/navigation/CompactNavigationContainer.kt
================================================
package com.infinitepower.newquiz.ui.navigation

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import com.infinitepower.newquiz.core.navigation.NavigationItem
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizScreenDestination
import com.infinitepower.newquiz.ui.components.DiamondsCounter
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.launch

/**
 * Container with navigation bar and modal drawer
 */
@Composable
@ExperimentalMaterial3Api
internal fun CompactContainer(
    navigator: DestinationsNavigator,
    navController: NavController,
    primaryItems: ImmutableList<NavigationItem.Item>,
    otherItems: ImmutableList<NavigationItem>,
    selectedItem: NavigationItem.Item?,
    userDiamonds: UInt = 0u,
    drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
    snackbarHostState: SnackbarHostState,
    content: @Composable (PaddingValues) -> Unit
) {
    val scope = rememberCoroutineScope()

    val text = selectedItem?.text?.let { id ->
        stringResource(id = id)
    } ?: "NewQuiz"

    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
        rememberTopAppBarState()
    )

    ModalNavigationDrawer(
        drawerState = drawerState,
        drawerContent = {
            NavigationDrawerContent(
                modifier = Modifier.fillMaxHeight(),
                permanent = false,
                selectedItem = selectedItem,
                items = otherItems,
                onItemClick = { item ->
                    scope.launch { drawerState.close() }
                    navigator.navigate(item.direction)
                },
            )
        }
    ) {
        Scaffold(
            modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
            snackbarHost = {
                SnackbarHost(hostState = snackbarHostState)
            },
            topBar = {
                CenterAlignedTopAppBar(
                    title = {
                        Text(text = text)
                    },
                    scrollBehavior = scrollBehavior,
                    navigationIcon = {
                        IconButton(
                            onClick = {
                                scope.launch { drawerState.open() }
                            }
                        ) {
                            Icon(
                                imageVector = Icons.Rounded.Menu,
                                contentDescription = "Open menu"
                            )
                        }
                    },
                    actions = {
                        DiamondsCounter(
                            diamonds = userDiamonds,
                            modifier = Modifier
                        )
                    }
                )
            },
            bottomBar = {
                CompactBottomBar(
                    selectedItem = selectedItem,
                    primaryItems = primaryItems,
                    navController = navController
                )
            },
            content = content
        )
    }
}

@Composable
private fun CompactBottomBar(
    modifier: Modifier = Modifier,
    selectedItem: NavigationItem.Item?,
    primaryItems: ImmutableList<NavigationItem.Item>,
    navController: NavController
) {
    NavigationBar(
        modifier = modifier,
    ) {
        primaryItems.forEach { item ->
            NavigationBarItem(
                selected = item == selectedItem,
                onClick = {
                    navController.navigate(item.direction.route) {
                        // Pop up to the start destination of the graph to
                        // avoid building up a large stack of destinations
                        // on the back stack as users select items
                        val startDestination = navController.graph.startDestinationRoute
                        popUpTo(startDestination ?: MultiChoiceQuizScreenDestination.route)
                        // Avoid multiple copies of the same destination when re-selecting the same item
                        launchSingleTop = true
                    }
                },
                icon = {
                    Icon(
                        imageVector = item.getIcon(item == selectedItem),
                        contentDescription = stringResource(id = item.text)
                    )
                }
            )
        }
    }
}

@Composable
@PreviewLightDark
@OptIn(ExperimentalMaterial3Api::class)
private fun CompactContainerPreview() {
    val otherItems = getOtherItems()

    val selectedItem = otherItems
        .filterIsInstance<NavigationItem.Item>()
        .firstOrNull()

    NewQuizTheme {
        Surface {
            CompactContainer(
                navController = rememberNavController(),
                navigator = EmptyDestinationsNavigator,
                content = {
                    Text(text = "NewQuiz")
                },
                primaryItems = getPrimaryItems(),
                otherItems = otherItems,
                selectedItem = selectedItem,
                userDiamonds = 100u,
                snackbarHostState = SnackbarHostState()
            )
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/navigation/ExpandedNavigationContainer.kt
================================================
package com.infinitepower.newquiz.ui.navigation

import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.PermanentNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.infinitepower.newquiz.core.navigation.NavigationItem
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.ui.components.DiamondsCounter
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

/**
 * Container with permanent navigation drawer
 */
@Composable
@ExperimentalMaterial3Api
internal fun ExpandedContainer(
    navigator: DestinationsNavigator,
    primaryItems: ImmutableList<NavigationItem.Item>,
    otherItems: ImmutableList<NavigationItem>,
    selectedItem: NavigationItem.Item?,
    userDiamonds: UInt = 0u,
    snackbarHostState: SnackbarHostState,
    content: @Composable (PaddingValues) -> Unit
) {
    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
        rememberTopAppBarState()
    )

    val text = selectedItem?.text?.let { id ->
        stringResource(id = id)
    } ?: "NewQuiz"

    val allNavigationItems = remember(primaryItems, otherItems) {
        (primaryItems + otherItems).toImmutableList()
    }

    PermanentNavigationDrawer(
        drawerContent = {
            NavigationDrawerContent(
                modifier = Modifier.fillMaxHeight(),
                permanent = true,
                selectedItem = selectedItem,
                items = allNavigationItems,
                onItemClick = { item ->
                    navigator.navigate(item.direction)
                },
            )
        }
    ) {
        Scaffold(
            modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
            snackbarHost = {
                SnackbarHost(hostState = snackbarHostState)
            },
            topBar = {
                CenterAlignedTopAppBar(
                    title = {
                        Text(text = text)
                    },
                    scrollBehavior = scrollBehavior,
                    actions = {
                        DiamondsCounter(
                            diamonds = userDiamonds,
                            modifier = Modifier
                        )
                    }
                )
            },
            content = content
        )
    }
}

@Composable
@Preview(
    showBackground = true,
    device = "spec:width=1280dp,height=800dp,dpi=480",
    group = "Expanded"
)
@Preview(
    showBackground = true,
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    device = "spec:width=1280dp,height=800dp,dpi=480",
    group = "Expanded"
)
@OptIn(ExperimentalMaterial3Api::class)
private fun MediumContainerPreview() {
    val otherItems = getOtherItems()

    val selectedItem = otherItems
        .filterIsInstance<NavigationItem.Item>()
        .firstOrNull()

    NewQuizTheme {
        Surface {
            ExpandedContainer(
                navigator = EmptyDestinationsNavigator,
                content = {
                    Text(text = "NewQuiz")
                },
                primaryItems = getPrimaryItems(),
                otherItems = otherItems,
                selectedItem = selectedItem,
                userDiamonds = 100u,
                snackbarHostState = SnackbarHostState()
            )
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/navigation/MediumNavigationContainer.kt
================================================
package com.infinitepower.newquiz.ui.navigation

import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.infinitepower.newquiz.core.navigation.NavigationItem
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.ui.components.DiamondsCounter
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.launch

/**
 * Container with navigation rail and modal drawer
 */
@Composable
@ExperimentalMaterial3Api
internal fun MediumContainer(
    navigator: DestinationsNavigator,
    primaryItems: ImmutableList<NavigationItem.Item>,
    otherItems: ImmutableList<NavigationItem>,
    selectedItem: NavigationItem.Item?,
    userDiamonds: UInt = 0u,
    drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
    snackbarHostState: SnackbarHostState,
    content: @Composable (PaddingValues) -> Unit
) {
    val scope = rememberCoroutineScope()

    val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
        rememberTopAppBarState()
    )

    val text = selectedItem?.text?.let { id ->
        stringResource(id = id)
    } ?: "NewQuiz"

    ModalNavigationDrawer(
        drawerState = drawerState,
        drawerContent = {
            NavigationDrawerContent(
                modifier = Modifier.fillMaxHeight(),
                permanent = false,
                selectedItem = selectedItem,
                items = otherItems,
                onItemClick = { item ->
                    scope.launch { drawerState.close() }
                    navigator.navigate(item.direction)
                }
            )
        }
    ) {
        Row {
            NavigationRail(
                header = {
                    IconButton(
                        onClick = {
                            scope.launch { drawerState.open() }
                        }
                    ) {
                        Icon(
                            imageVector = Icons.Rounded.Menu,
                            contentDescription = "Open menu"
                        )
                    }
                }
            ) {
                primaryItems.forEach { item ->
                    NavigationRailItem(
                        selected = item == selectedItem,
                        onClick = { navigator.navigate(item.direction) },
                        icon = {
                            Icon(
                                imageVector = item.getIcon(item == selectedItem),
                                contentDescription = stringResource(id = item.text)
                            )
                        }
                    )
                }
            }

            Scaffold(
                modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
                snackbarHost = {
                    SnackbarHost(hostState = snackbarHostState)
                },
                topBar = {
                    CenterAlignedTopAppBar(
                        scrollBehavior = scrollBehavior,
                        title = {
                            Text(text = text)
                        },
                        actions = {
                            DiamondsCounter(
                                diamonds = userDiamonds,
                                modifier = Modifier
                            )
                        }
                    )
                },
                content = content
            )
        }
    }
}

@Composable
@Preview(
    showBackground = true,
    device = "spec:width=673.5dp,height=841dp,dpi=480",
    group = "Medium"
)
@Preview(
    showBackground = true,
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    device = "spec:width=673.5dp,height=841dp,dpi=480",
    group = "Medium"
)
@OptIn(ExperimentalMaterial3Api::class)
private fun MediumContainerPreview() {
    val otherItems = getOtherItems(dailyChallengeClaimCount = 5)

    val selectedItem = otherItems
        .filterIsInstance<NavigationItem.Item>()
        .firstOrNull()

    NewQuizTheme {
        Surface {
            MediumContainer(
                navigator = EmptyDestinationsNavigator,
                content = {
                    Text(text = "NewQuiz")
                },
                primaryItems = getPrimaryItems(),
                otherItems = otherItems,
                selectedItem = selectedItem,
                snackbarHostState = SnackbarHostState()
            )
        }
    }
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/navigation/NavDrawerContent.kt
================================================
package com.infinitepower.newquiz.ui.navigation

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.Badge
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.PermanentDrawerSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import com.infinitepower.newquiz.core.navigation.NavigationItem
import com.infinitepower.newquiz.core.theme.spacing
import kotlinx.collections.immutable.ImmutableList
import com.infinitepower.newquiz.core.R as CoreR

@Composable
@ExperimentalMaterial3Api
internal fun NavigationDrawerContent(
    modifier: Modifier = Modifier,
    onItemClick: (item: NavigationItem.Item) -> Unit,
    permanent: Boolean = false,
    items: ImmutableList<NavigationItem>,
    selectedItem: NavigationItem.Item?
) {
    NavigationDrawerContainer(
        modifier = modifier,
        permanent = permanent
    ) {
        NavigationDrawerContent(
            items = items,
            selectedItem = selectedItem,
            onItemClick = onItemClick,
        )
    }
}

@Composable
@ExperimentalMaterial3Api
private fun NavigationDrawerContainer(
    modifier: Modifier = Modifier,
    permanent: Boolean,
    content: @Composable ColumnScope.() -> Unit
) {
    if (permanent) {
        PermanentDrawerSheet(
            modifier = modifier,
            content = content
        )
    } else {
        ModalDrawerSheet(
            modifier = modifier,
            content = content
        )
    }
}

@Composable
@ExperimentalMaterial3Api
private fun NavigationDrawerContent(
    modifier: Modifier = Modifier,
    onItemClick: (item: NavigationItem.Item) -> Unit,
    items: ImmutableList<NavigationItem>,
    selectedItem: NavigationItem.Item?,
) {
    LazyColumn(
        modifier = modifier,
        contentPadding = NavigationDrawerItemDefaults.ItemPadding
    ) {
        item {
            Column(
                modifier = Modifier.padding(vertical = MaterialTheme.spacing.large)
            ) {
                Text(
                    text = stringResource(id = CoreR.string.app_name),
                    style = MaterialTheme.typography.headlineSmall
                )
            }
        }

        itemsIndexed(items = items) { index, item ->
            val text = stringResource(id = item.text)

            when (item) {
                is NavigationItem.Label -> {
                    if (items.getOrNull(index - 1) is NavigationItem.Item) {
                        Spacer(modifier = Modifier.height(MaterialTheme.spacing.medium))
                    }
                    NavigationDrawerLabel(text = text)
                    Spacer(modifier = Modifier.height(MaterialTheme.spacing.medium))
                }

                is NavigationItem.Item -> {
                    NavigationDrawerItem(
                        icon = {
                            Icon(
                                imageVector = item.getIcon(item == selectedItem),
                                contentDescription = text
                            )
                        },
                        label = { Text(text = text) },
                        selected = item == selectedItem,
                        onClick = { onItemClick(item) },
                        badge = if (item.badge != null && item.badge.value > 0) {
                            {
                                Badge {
                                    Text(
                                        text = item.badge.value.toString(),
                                        modifier = Modifier.semantics {
                                            contentDescription = item.badge.description
                                        }
                                    )
                                }
                            }
                        } else {
                            null
                        }
                    )
                }
            }
        }
    }
}

@Composable
private fun NavigationDrawerLabel(
    text: String
) {
    Text(
        text = text,
        style = MaterialTheme.typography.labelLarge
    )
}


================================================
FILE: app/src/main/java/com/infinitepower/newquiz/ui/navigation/NavigationContainer.kt
================================================
package com.infinitepower.newquiz.ui.navigation

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.List
import androidx.compose.material.icons.automirrored.rounded.ListAlt
import androidx.compose.material.icons.outlined.Compare
import androidx.compose.material.icons.outlined.ViewModule
import androidx.compose.material.icons.rounded.Image
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.Route
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material.icons.rounded.Today
import androidx.compose.material.icons.rounded.ViewModule
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavController
import com.infinitepower.newquiz.comparison_quiz.destinations.ComparisonQuizListScreenDestination
import com.infinitepower.newquiz.core.R
import com.infinitepower.newquiz.core.navigation.NavDrawerBadgeItem
import com.infinitepower.newquiz.core.navigation.NavigationItem
import com.infinitepower.newquiz.core.navigation.ScreenType
import com.infinitepower.newquiz.core.ui.ObserveAsEvents
import com.infinitepower.newquiz.core.ui.SnackbarController
import com.infinitepower.newquiz.core.util.asString
import com.infinitepower.newquiz.feature.daily_challenge.destinations.DailyChallengeScreenDestination
import com.infinitepower.newquiz.feature.maze.destinations.MazeScreenDestination
import com.infinitepower.newquiz.feature.profile.destinations.ProfileScreenDestination
import com.infinitepower.newquiz.feature.settings.destinations.SettingsScreenDestination
import com.infinitepower.newquiz.multi_choice_quiz.destinations.MultiChoiceQuizListScreenDestination
import com.infinitepower.newquiz.wordle.destinations.WordleListScreenDestination
import com.ramcosta.composedestinations.spec.DestinationSpec
import com.ramcosta.composedestinations.utils.currentDestinationAsState
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch

internal fun getPrimaryItems(): ImmutableList<NavigationItem.Item> = persistentListOf(
    NavigationItem.Item(
        text = R.string.multi_choice_quiz,
        selectedIcon = Icons.AutoMirrored.Rounded.ListAlt,
        unselectedIcon = Icons.AutoMirrored.Rounded.List,
        direction = MultiChoiceQuizListScreenDestination,
        primary = true
    ),
    NavigationItem.Item(
        text = R.string.wordle,
        selectedIcon = Icons.Rounded.ViewModule,
        unselectedIcon = Icons.Outlined.ViewModule,
        direction = WordleListScreenDestination,
        primary = true
    ),
    NavigationItem.Item(
        text = R.string.comparison_quiz,
        selectedIcon = Icons.Rounded.Image,
        unselectedIcon = Icons.Outlined.Compare,
        direction = ComparisonQuizListScreenDestination,
        primary = true
    ),
)

internal fun getOtherItems(
    dailyChallengeClaimCount: Int = 0
): ImmutableList<NavigationItem> = persistentListOf(
    NavigationItem.Item(
        text = R.string.maze,
        selectedIcon = Icons.Rounded.Route,
        direction = MazeScreenDestination,
        screenType = ScreenType.NAVIGATION_HIDDEN
    ),
    NavigationItem.Item(
        text = R.string.daily_challenge,
        selectedIcon = Icons.Rounded.Today,
        direction = DailyChallengeScreenDestination,
        screenType = ScreenType.NAVIGATION_HIDDEN,
        badge = NavDrawerBadgeItem(
            value = dailyChallengeClaimCount,
            description = "Daily challenge claim count"
        )
    ),
    NavigationItem.Label(text = R.string.user),
    NavigationItem.Item(
        text = R.string.profile,
        selectedIcon = Icons.Rounded.Person,
        direction = ProfileScreenDestination,
        screenType = ScreenType.NAVIGATION_HIDDEN
    ),
    NavigationItem.Label(text = R.string.other),
    NavigationItem.Item(
        text = R.string.settings,
        selectedIcon = Icons.Rounded.Settings,
        direction = SettingsScreenDestination(),
        screenType = ScreenType.NAVIGATION_HIDDEN
    )
)

private fun List<NavigationItem>.getNavigationItemBy(
    route: DestinationSpec<*>?
): NavigationItem.Item? = filterIsInstance<NavigationItem.Item>()
    .find { item -> item.direction == route }

@Composable
@ExperimentalMaterial3Api
internal fun NavigationContainer(
    navController: NavController,
    windowWidthSize: WindowWidthSizeClass,
    dailyChallengeClaimCount: Int,
    userDiamonds: UInt,
    content: @Composable (PaddingValues) -> Unit
) {
    val scope = rememberCoroutineScope()

    val navigator = navController.rememberDestinationsNavigator()
    val destination by navController.currentDestinationAsState()

    val primaryItems = remember { getPrimaryItems() }

    val otherItems = remember(dailyChallengeClaimCount) {
        getOtherItems(dailyChallengeClaimCount)
    }

    val selectedItem = remember(primaryItems, otherItems, destination) {
        primaryItems.getNavigationItemBy(destination)
            ?: otherItems.getNavigationItemBy(destination)
    }

    val navigationVisible = remember(selectedItem) {
        selectedItem != null && selectedItem.screenType == ScreenType.NORMAL
    }

    val context = LocalContext.current

    val snackbarHostState = remember { SnackbarHostState() }
    ObserveAsEvents(flow = SnackbarController.events, snackbarHostState) { event ->
        scope.launch {
            snackbarHostState.currentSnackbarData?.dismiss()

            val result = snackbarHostState.showSnackbar(
                message = event.message.asString(context),
                actionLabel = event.action?.name?.asString(context),
                withDismissAction = event.withDismissAction,
                duration = event.duration
            )

            if (result == SnackbarResult.ActionPerformed) {
                event.action?.action?.invoke()
            }
        }
    }

    if (navigationVisible) {
        when (windowWidthSize) {
            WindowWidthSizeClass.Compact -> CompactContainer(
                navigator = navigator,
                navController = navController,
                primaryItems = primaryItems,
                otherItems = otherItems,
                selectedItem = selectedItem,
                userDiamonds = userDiamonds,
                snackbarHostState = snackbarHostState,
                content = content
            )

            WindowWidthSizeClass.Medium -> MediumContainer(
                navigator = navigator,
                primaryItems = primaryItems,
                otherItems = otherItems,
                selectedItem = selectedItem,
                userDiamonds = userDiamonds,
                snackbarHostState = snackbarHostState,
                content = content
            )

            WindowWidthSizeClass.Expanded -> ExpandedContainer(
                navigator = navigator,
                primaryItems = primaryItems,
                otherItems = otherItems,
                selectedItem = selectedItem,
                userDiamonds = userDiamonds,
                snackbarHostState = snackbarHostState,
                content = content
            )
        }
    } else {
        Scaffold(
            content = content,
            snackbarHost = {
                SnackbarHost(hostState = snackbarHostState)
            },
            // This Scaffold only manages Snackbar display and shouldn't handle window insets.
            // Insets are delegated to parent layouts or other Scaffolds in the composable hierarchy.
            contentWindowInsets = WindowInsets(0, 0, 0, 0)
        )
    }
}


================================================
FILE: app/src/main/res/drawable/round_password_24.xml
================================================
<vector
    android:height="24dp"
    android:tint="#000000"
    android:viewportHeight="24"
    android:viewportWidth="24"
    android:width="24dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:ignore="VectorPath">
    <path android:fillColor="@android:color/white" android:pathData="M3,17h18c0.55,0 1,0.45 1,1v0c0,0.55 -0.45,1 -1,1H3c-0.55,0 -1,-0.45 -1,-1v0C2,17.45 2.45,17 3,17zM2.5,12.57c0.36,0.21 0.82,0.08 1.03,-0.28L4,11.47l0.48,0.83c0.21,0.36 0.67,0.48 1.03,0.28l0,0c0.36,-0.21 0.48,-0.66 0.28,-1.02L5.3,10.72h0.95C6.66,10.72 7,10.38 7,9.97v0c0,-0.41 -0.34,-0.75 -0.75,-0.75H5.3L5.77,8.4C5.98,8.04 5.86,7.58 5.5,7.37l0,0C5.14,7.17 4.68,7.29 4.47,7.65L4,8.47L3.53,7.65C3.32,7.29 2.86,7.17 2.5,7.37l0,0C2.14,7.58 2.02,8.04 2.23,8.4L2.7,9.22H1.75C1.34,9.22 1,9.56 1,9.97v0c0,0.41 0.34,0.75 0.75,0.75H2.7l-0.48,0.83C2.02,11.91 2.14,12.37 2.5,12.57L2.5,12.57zM10.5,12.57L10.5,12.57c0.36,0.21 0.82,0.08 1.03,-0.28L12,11.47l0.48,0.83c0.21,0.36 0.67,0.48 1.03,0.28l0,0c0.36,-0.21 0.48,-0.66 0.28,-1.02l-0.48,-0.83h0.95c0.41,0 0.75,-0.34 0.75,-0.75v0c0,-0.41 -0.34,-0.75 -0.75,-0.75H13.3l0.47,-0.82c0.21,-0.36 0.08,-0.82 -0.27,-1.03l0,0c-0.36,-0.21 -0.82,-0.08 -1.02,0.27L12,8.47l-0.47,-0.82c-0.21,-0.36 -0.67,-0.48 -1.02,-0.27l0,0c-0.36,0.21 -0.48,0.67 -0.27,1.03l0.47,0.82H9.75C9.34,9.22 9,9.56 9,9.97v0c0,0.41 0.34,0.75 0.75,0.75h0.95l-0.48,0.83C10.02,11.91 10.14,12.37 10.5,12.57zM23,9.97c0,-0.41 -0.34,-0.75 -0.75,-0.75H21.3l0.47,-0.82c0.21,-0.36 0.08,-0.82 -0.27,-1.03l0,0c-0.36,-0.21 -0.82,-0.08 -1.02,0.27L20,8.47l-0.47,-0.82c-0.21,-0.36 -0.67,-0.48 -1.02,-0.27l0,0c-0.36,0.21 -0.48,0.67 -0.27,1.03l0.47,0.82h-0.95C17.34,9.22 17,9.56 17,9.97v0c0,0.41 0.34,0.75 0.75,0.75h0.95l-0.48,0.83c-0.21,0.36 -0.08,0.82 0.28,1.02l0,0c0.36,0.21 0.82,0.08 1.03,-0.28L20,11.47l0.48,0.83c0.21,0.36 0.67,0.48 1.03,0.28l0,0c0.36,-0.21 0.48,-0.66 0.28,-1.02l-0.48,-0.83h0.95C22.66,10.72 23,10.38 23,9.97L23,9.97z"/>
</vector>


================================================
FILE: app/src/main/res/drawable/round_play_circle_24.xml
================================================
<vector android:height="24dp" android:tint="#000000"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM9.5,14.67V9.33c0,-0.79 0.88,-1.27 1.54,-0.84l4.15,2.67c0.61,0.39 0.61,1.29 0,1.68l-4.15,2.67C10.38,15.94 9.5,15.46 9.5,14.67z"/>
</vector>


================================================
FILE: app/src/main/res/drawable/round_quiz_24.xml
================================================
<vector android:height="24dp" android:tint="#000000"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M17,20H4V7c0,-0.55 -0.45,-1 -1,-1S2,6.45 2,7v13c0,1.1 0.9,2 2,2h13c0.55,0 1,-0.45 1,-1S17.55,20 17,20z"/>
    <path android:fillColor="@android:color/white" android:pathData="M20,2H8C6.9,2 6,2.9 6,4v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2zM14.01,15c-0.59,0 -1.05,-0.47 -1.05,-1.05c0,-0.59 0.47,-1.04 1.05,-1.04c0.59,0 1.04,0.45 1.04,1.04C15.04,14.53 14.6,15 14.01,15zM16.51,8.83c-0.63,0.93 -1.23,1.21 -1.56,1.81c-0.08,0.14 -0.13,0.26 -0.16,0.49c-0.05,0.39 -0.36,0.68 -0.75,0.68h-0.03c-0.44,0 -0.79,-0.38 -0.75,-0.82c0.03,-0.28 0.09,-0.57 0.25,-0.84c0.41,-0.73 1.18,-1.16 1.63,-1.8c0.48,-0.68 0.21,-1.94 -1.14,-1.94c-0.61,0 -1.01,0.32 -1.26,0.7c-0.19,0.29 -0.57,0.39 -0.89,0.25l0,0c-0.42,-0.18 -0.6,-0.7 -0.34,-1.07C12.02,5.55 12.87,5 13.99,5c1.23,0 2.08,0.56 2.51,1.26C16.87,6.87 17.08,7.99 16.51,8.83z"/>
</vector>


================================================
FILE: app/src/main/res/resources.properties
================================================
unqualifiedResLocale=en

================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
</resources>

================================================
FILE: app/src/main/res/values/leak_canary.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

================================================
FILE: app/src/main/res/values/splash_screen.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.NewQuiz.Starting" parent="Theme.SplashScreen">
        <item name="windowSplashScreenBackground">@color/white</item>
        <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher_round</item>
        <item name="postSplashScreenTheme">@style/Theme.NewQuiz</item>
    </style>
</resources>

================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name" translatable="false">NewQuiz</string>
</resources>

================================================
FILE: app/src/main/res/values-night/splash_screen.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.NewQuiz.Starting" parent="Theme.SplashScreen">
        <item name="windowSplashScreenBackground">@color/black</item>
        <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher_round</item>
        <item name="postSplashScreenTheme">@style/Theme.NewQuiz</item>
    </style>
</resources>

================================================
FILE: app/src/main/res/xml-v25/shortcuts.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="quick_quiz"
        android:enabled="true"
        android:icon="@drawable/round_play_circle_24"
        android:shortcutShortLabel="@string/maze"
        android:shortcutLongLabel="@string/maze">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.infinitepower.newquiz"
            android:targetClass="com.infinitepower.newquiz.ui.main.MainActivity"
            android:data="newquiz://maze"/>
    </shortcut>

    <shortcut
        android:shortcutId="quick_quiz"
        android:enabled="true"
        android:icon="@drawable/round_quiz_24"
        android:shortcutShortLabel="@string/quick_quiz"
        android:shortcutLongLabel="@string/quick_quiz">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.infinitepower.newquiz"
            android:targetClass="com.infinitepower.newquiz.ui.main.MainActivity"
            android:data="newquiz://quickquiz"/>
    </shortcut>

    <shortcut
        android:shortcutId="wordle_infinite"
        android:enabled="true"
        android:icon="@drawable/round_password_24"
        android:shortcutShortLabel="@string/wordle_infinite"
        android:shortcutLongLabel="@string/wordle_infinite">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.infinitepower.newquiz"
            android:targetClass="com.infinitepower.newquiz.ui.main.MainActivity"
            android:data="newquiz://wordleinfinite"/>
    </shortcut>
</shortcuts>

================================================
FILE: build-logic/.gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/convention/build
/captures
.externalNativeBuild
.cxx
local.properties


================================================
FILE: build-logic/README.md
================================================
# Build logic

The build-logic folder defines project-specific convention plugins, used to keep a single source of truth for common module configurations.

Based in the [Now in Android](https://github.com/android/nowinandroid) project.

================================================
FILE: build-logic/convention/build.gradle.kts
================================================
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    `kotlin-dsl`
    alias(libs.plugins.detekt)
}

group = "com.infinitepower.newquiz.buildlogic"

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

kotlin {
    compilerOptions {
        jvmTarget = JvmTarget.JVM_17
    }
}

tasks {
    validatePlugins {
        enableStricterValidation = true
        failOnWarning = true
    }
}

dependencies {
    compileOnly(libs.android.gradlePlugin)
    compileOnly(libs.firebase.crashlytics.gradlePlugin)
    compileOnly(libs.firebase.performance.gradlePlugin)
    compileOnly(libs.kotlin.gradlePlugin)
    compileOnly(libs.ksp.gradlePlugin)
    compileOnly(libs.compose.gradlePlugin)
    implementation(libs.detekt.gradlePlugin)
}

detekt {
    buildUponDefaultConfig = true
    config.from(file("../../detekt.yml"))
}

gradlePlugin {
    plugins {
        register("androidApplicationCompose") {
            id = "newquiz.android.application.compose"
            implementationClass = "AndroidApplicationComposeConventionPlugin"
        }
        register("androidApplication") {
            id = "newquiz.android.application"
            implementationClass = "AndroidApplicationConventionPlugin"
        }
        register("androidLibraryCompose") {
            id = "newquiz.android.library.compose"
            implementationClass = "AndroidLibraryComposeConventionPlugin"
        }
        register("androidLibrary") {
            id = "newquiz.android.library"
            implementationClass = "AndroidLibraryConventionPlugin"
        }
        register("androidHilt") {
            id = "newquiz.android.hilt"
            implementationClass = "AndroidHiltConventionPlugin"
        }
        register("androidRoom") {
            id = "newquiz.android.room"
            implementationClass = "AndroidRoomConventionPlugin"
        }
        register("androidFirebase") {
            id = "newquiz.android.application.firebase"
            implementationClass = "AndroidApplicationFirebaseConventionPlugin"
        }
        register("jvmLibrary") {
            id = "newquiz.jvm.library"
            implementationClass = "JvmLibraryConventionPlugin"
        }
        register("kotlinSerialization") {
            id = "newquiz.kotlin.serialization"
            implementationClass = "KotlinSerializationConventionPlugin"
        }
        register("androidComposeDestinations") {
            id = "newquiz.android.compose.destinations"
            implementationClass = "AndroidComposeDestinationsConventionPlugin"
        }
        register("androidFeature") {
            id = "newquiz.android.feature"
            implementationClass = "AndroidFeatureConventionPlugin"
        }
        register("detekt") {
            id = "newquiz.detekt"
            implementationClass = "DetektConventionPlugin"
        }
    }
}

================================================
FILE: build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
================================================
import com.android.build.api.dsl.ApplicationExtension
import com.infinitepower.newquiz.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType

class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply("com.android.application")

            val extension = extensions.getByType<ApplicationExtension>()
            configureAndroidCompose(extension)
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
================================================
import com.android.build.api.dsl.ApplicationExtension
import com.infinitepower.newquiz.NewQuizFlavor
import com.infinitepower.newquiz.ProjectConfig
import com.infinitepower.newquiz.configureFlavors
import com.infinitepower.newquiz.configureKotlinAndroid
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.support.uppercaseFirstChar

class AndroidApplicationConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("com.android.application")
                apply("org.jetbrains.kotlin.android")
            }

            extensions.configure<ApplicationExtension> {
                configureKotlinAndroid(this)
                configureFlavors(this)

                defaultConfig {
                    targetSdk = ProjectConfig.targetSdk
                }
            }

            // Apply the Firebase plugin only for the "Normal" build type
            val gradleTaskRequests = gradle.startParameter.taskRequests.toString()
            val normalFlavor = NewQuizFlavor.normal.name.uppercaseFirstChar()

            // Check if the flavor name is in the gradle task requests,
            // like "assembleNormalDebug" or "assembleFossDebug"
            if (gradleTaskRequests.contains(normalFlavor)) {
                apply(plugin = "newquiz.android.application.firebase")
                logger.info("Applied Firebase plugin for normal build type")
            }

            tasks.register("testAllUnitTest") {
                // Only run debug tests
                dependsOn(
                    getTasksByName("testNormalDebugUnitTest", true),
                    getTasksByName("testFossDebugUnitTest", true),
                )
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt
================================================
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.libs
import com.infinitepower.newquiz.normalImplementation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class AndroidApplicationFirebaseConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("com.google.gms.google-services")
                apply("com.google.firebase.firebase-perf")
                apply("com.google.firebase.crashlytics")
            }

            dependencies {
                val bom = libs.findLibrary("firebase-bom").get()

                implementation(platform(bom))
                normalImplementation(libs.findLibrary("firebase-analytics").get())
                normalImplementation(libs.findLibrary("firebase-crashlytics").get())
                normalImplementation(libs.findLibrary("firebase-perf").get())
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidComposeDestinationsConventionPlugin.kt
================================================
import com.google.devtools.ksp.gradle.KspExtension
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.ksp
import com.infinitepower.newquiz.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies

class AndroidComposeDestinationsConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            plugins.apply("com.google.devtools.ksp")

            dependencies {
                implementation(libs.findLibrary("compose.destinations.core").get())
                ksp(libs.findLibrary("compose.destinations.ksp").get())
            }

            extensions.configure<KspExtension> {
                val mode = "destinations"
                val moduleName = target.name

                logger.info("Configuring compose-destinations for $moduleName, with mode: $mode")

                arg("compose-destinations.mode", mode)
                arg("compose-destinations.moduleName", moduleName)
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
================================================
import com.infinitepower.newquiz.debugImplementation
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class AndroidFeatureConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply {
                apply("newquiz.android.library.compose")
                apply("newquiz.android.hilt")
            }

            dependencies {
                implementation(project(":model"))
                implementation(project(":core"))
                implementation(project(":core:analytics"))

                implementation(libs.findLibrary("androidx.compose.foundation").get())
                implementation(libs.findLibrary("androidx.compose.material3").get())
                implementation(libs.findLibrary("androidx.compose.runtime").get())
                implementation(libs.findLibrary("androidx.compose.ui.tooling.preview").get())

                debugImplementation(libs.findLibrary("androidx.compose.ui.tooling").get())

                implementation(libs.findLibrary("hilt.navigationCompose").get())
                implementation(libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
                implementation(libs.findLibrary("androidx.lifecycle.viewModelCompose").get())

                implementation(libs.findLibrary("kotlinx.coroutines.android").get())
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt
================================================
import com.infinitepower.newquiz.androidTestImplementation
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.ksp
import com.infinitepower.newquiz.kspAndroidTest
import com.infinitepower.newquiz.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class AndroidHiltConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("dagger.hilt.android.plugin")
                apply("com.google.devtools.ksp")
            }

            dependencies {
                // Base dependencies of hilt
                implementation(libs.findLibrary("hilt.android").get())
                ksp(libs.findLibrary("hilt.compiler").get())

                // Dependencies for testing
                kspAndroidTest(libs.findLibrary("hilt.compiler").get())
                androidTestImplementation(libs.findLibrary("hilt.android.testing").get())
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
================================================
import com.android.build.api.dsl.LibraryExtension
import com.infinitepower.newquiz.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("newquiz.android.library")
            }

            extensions.configure<LibraryExtension> {
                configureAndroidCompose(this)
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
================================================
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.infinitepower.newquiz.ProjectConfig
import com.infinitepower.newquiz.androidTestImplementation
import com.infinitepower.newquiz.configureFlavors
import com.infinitepower.newquiz.configureKotlinAndroid
import com.infinitepower.newquiz.disableUnnecessaryAndroidTests
import com.infinitepower.newquiz.libs
import com.infinitepower.newquiz.testImplementation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin
import org.gradle.kotlin.dsl.withType

class AndroidLibraryConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("com.android.library")
                apply("org.jetbrains.kotlin.android")
            }

            extensions.configure<LibraryExtension> {
                configureKotlinAndroid(this)
                configureFlavors(this)

                defaultConfig {
                    targetSdk = ProjectConfig.targetSdk
                    testInstrumentationRunner = "com.infinitepower.newquiz.core.testing.NewQuizTestRunner"
                }
            }

            extensions.configure<LibraryAndroidComponentsExtension> {
                disableUnnecessaryAndroidTests(target)
            }

            dependencies {
                // Test libraries
                testImplementation(kotlin("test"))
                testImplementation(libs.findLibrary("google.truth").get())
                testImplementation(libs.findLibrary("mockk").get())
                testImplementation(libs.findLibrary("kotlinx.coroutines.test").get())
                testImplementation(libs.findLibrary("junit.jupiter.params").get())
                testImplementation(libs.findLibrary("turbine").get())

                androidTestImplementation(kotlin("test"))
                androidTestImplementation(libs.findLibrary("google.truth").get())
                androidTestImplementation(libs.findLibrary("mockk.android").get())
                androidTestImplementation(libs.findLibrary("kotlinx.coroutines.test").get())
                androidTestImplementation(libs.findLibrary("androidx.test.runner").get())
                androidTestImplementation(libs.findLibrary("androidx.test.rules").get())
                androidTestImplementation(libs.findLibrary("androidx.compose.ui.test").get())
                androidTestImplementation(libs.findLibrary("turbine").get())
                androidTestImplementation(project(":core:testing"))

                // Fix for problem of duplicate classes with guava
                modules {
                    module("com.google.guava:listenablefuture") {
                        replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
                    }
                }
            }

            tasks.withType<Test> {
                useJUnitPlatform()
            }

            tasks.register("testAllUnitTest") {
                // Only run debug tests
                dependsOn(
                    getTasksByName("testNormalDebugUnitTest", true),
                    getTasksByName("testFossDebugUnitTest", true),
                )
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt
================================================
import com.google.devtools.ksp.gradle.KspExtension
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.ksp
import com.infinitepower.newquiz.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.process.CommandLineArgumentProvider
import java.io.File

class AndroidRoomConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply("com.google.devtools.ksp")

            extensions.configure<KspExtension> {
                // The schemas directory contains a schema file for each version of the Room database.
                // This is required to enable Room auto migrations.
                // See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
                arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
            }

            dependencies {
                implementation(libs.findLibrary("room.runtime").get())
                implementation(libs.findLibrary("room.ktx").get())
                ksp(libs.findLibrary("room.compiler").get())
            }
        }
    }

    class RoomSchemaArgProvider(
        @get:InputDirectory
        @get:PathSensitive(PathSensitivity.RELATIVE)
        val schemaDir: File,
    ) : CommandLineArgumentProvider {
        override fun asArguments() = listOf("room.schemaLocation=${schemaDir.path}")
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt
================================================
import com.infinitepower.newquiz.libs
import io.gitlab.arturbosch.detekt.Detekt
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType

class DetektConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply(
                libs.findLibrary("detekt.gradlePlugin").get().get().group.toString()
            )

            tasks.withType<Detekt> {
                buildUponDefaultConfig = true
                basePath = target.rootProject.projectDir.absolutePath

                val localDetektConfig = target.file("detekt.yml")
                val rootDetektConfig = target.rootProject.file("detekt.yml")
                val rootDetektComposeConfig = target.rootProject.file("detekt-compose.yml")
                if (localDetektConfig.exists()) {
                    config.from(
                        localDetektConfig,
                        rootDetektConfig,
                        rootDetektComposeConfig
                    )
                } else {
                    config.from(rootDetektConfig, rootDetektComposeConfig)
                }

                reports {
                    sarif.required.set(true)
                }
            }

            dependencies {
                add("detektPlugins", libs.findLibrary("detekt.compose").get())
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/JvmLibraryConventionPlugin.kt
================================================
import com.infinitepower.newquiz.configureKotlinJvm
import com.infinitepower.newquiz.libs
import com.infinitepower.newquiz.testImplementation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType

class JvmLibraryConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("org.jetbrains.kotlin.jvm") // kotlin("jvm")
            }

            configureKotlinJvm()

            dependencies {
                // Test libraries
                testImplementation(kotlin("test"))
                testImplementation(libs.findLibrary("google.truth").get())
                testImplementation(libs.findLibrary("mockk").get())
                testImplementation(libs.findLibrary("kotlinx.coroutines.test").get())
                testImplementation(libs.findLibrary("junit.jupiter.params").get())
                testImplementation(libs.findLibrary("turbine").get())
            }

            tasks.withType<Test> {
                useJUnitPlatform()
            }


            tasks.register<Test>("testAllUnitTest") {
                dependsOn(
                    getTasksByName("test", true),
                )
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/KotlinSerializationConventionPlugin.kt
================================================
import com.infinitepower.newquiz.implementation
import com.infinitepower.newquiz.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class KotlinSerializationConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            plugins.apply("kotlinx-serialization")

            dependencies {
                implementation(libs.findLibrary("kotlinx.serialization.json").get())
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/AndroidCompose.kt
================================================
package com.infinitepower.newquiz

import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension

internal fun Project.configureAndroidCompose(
    applicationExtension: CommonExtension<*, *, *, *, *, *>
) {
    pluginManager.apply("org.jetbrains.kotlin.plugin.compose")

    applicationExtension.apply {
        buildFeatures {
            compose = true
        }

        dependencies {
            val bom = libs.findLibrary("androidx-compose-bom").get()
            implementation(platform(bom))
            androidTestImplementation(platform(bom))
            implementation(libs.findLibrary("androidx-compose-ui-tooling-preview").get())
            // Add ComponentActivity to debug manifest
            debugImplementation(libs.findLibrary("androidx-compose-ui-tooling").get())
        }

        testOptions {
            unitTests {
                isIncludeAndroidResources = true
            }
        }
    }

    extensions.configure<ComposeCompilerGradlePluginExtension> {
        fun Provider<String>.onlyIfTrue() = flatMap { provider { it.takeIf(String::toBoolean) } }
        fun Provider<*>.relativeToRootProject(dir: String) = flatMap {
            rootProject.layout.buildDirectory.dir(projectDir.toRelativeString(rootDir))
        }.map { it.dir(dir) }

        project.providers.gradleProperty("enableComposeCompilerMetrics").onlyIfTrue()
            .relativeToRootProject("compose-metrics")
            .let(metricsDestination::set)

        project.providers.gradleProperty("enableComposeCompilerReports").onlyIfTrue()
            .relativeToRootProject("compose-reports")
            .let(reportsDestination::set)

        stabilityConfigurationFile.set(rootProject.layout.projectDirectory.file("compose_compiler_config.conf"))

        enableStrongSkippingMode.set(true)
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/AndroidInstrumentedTests.kt
================================================
package com.infinitepower.newquiz

import com.android.build.api.variant.LibraryAndroidComponentsExtension
import org.gradle.api.Project

/**
 * Disable android tests if there is no androidTest folder.
 */
internal fun LibraryAndroidComponentsExtension.disableUnnecessaryAndroidTests(
    project: Project,
) = beforeVariants {
    it.enableAndroidTest = it.enableAndroidTest
            && project.projectDir.resolve("src/androidTest").exists()
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/Flavors.kt
================================================
package com.infinitepower.newquiz

import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ApplicationProductFlavor
import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.ProductFlavor

@Suppress("EnumEntryName", "EnumNaming")
enum class FlavorDimension {
    distribution,
    // translation
}

@Suppress("EnumEntryName", "EnumNaming")
enum class NewQuizFlavor(
    val dimension: FlavorDimension,
    val applicationIdSuffix: String? = null
) {
    normal(FlavorDimension.distribution),
    foss(FlavorDimension.distribution),

    // translation(FlavorDimension.translation),
    // noTranslation(FlavorDimension.translation),
}

fun configureFlavors(
    commonExtension: CommonExtension<*, *, *, *, *, *>,
    flavorConfigurationBlock: ProductFlavor.(flavor: NewQuizFlavor) -> Unit = {}
) {
    commonExtension.apply {
        flavorDimensions += FlavorDimension.values().map { it.name }

        productFlavors {
            NewQuizFlavor.values().forEach { flavor ->
                create(flavor.name) {
                    dimension = flavor.dimension.name
                    flavorConfigurationBlock(this, flavor)

                    if (this@apply is ApplicationExtension && this is ApplicationProductFlavor) {
                        if (flavor.applicationIdSuffix != null) {
                            applicationIdSuffix = flavor.applicationIdSuffix
                        }
                    }
                }
            }
        }
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/KotlinAndroid.kt
================================================
package com.infinitepower.newquiz

import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

internal fun Project.configureKotlinAndroid(
    commonExtension: CommonExtension<*, * , * , *, *, *>
) {
    commonExtension.apply {
        compileSdk = ProjectConfig.compileSdk

        defaultConfig {
            minSdk = ProjectConfig.minSdk
        }

        compileOptions {
            sourceCompatibility = ProjectConfig.javaVersionCompatibility
            targetCompatibility = ProjectConfig.javaVersionCompatibility

            isCoreLibraryDesugaringEnabled = true
        }

        packaging {
            resources {
                excludes += "/META-INF/{AL2.0,LGPL2.1}"
                excludes += "/META-INF/LICENSE.md"
                excludes += "/META-INF/LICENSE-notice.md"
            }
        }
    }

    configureKotlinAndroid()

    dependencies {
        coreLibraryDesugaring(libs.findLibrary("android.desugarJdkLibs").get())
    }
}

internal fun Project.configureKotlinJvm() {
    extensions.apply {
        configure<JavaPluginExtension> {
            sourceCompatibility = ProjectConfig.javaVersionCompatibility
            targetCompatibility = ProjectConfig.javaVersionCompatibility
        }

        configure<KotlinJvmProjectExtension> {
            jvmToolchain(ProjectConfig.jvmToolchainVersion)
        }
    }
}

private fun Project.configureKotlinAndroid() {
    tasks.withType<KotlinCompile>().configureEach {
        compilerOptions {
            jvmTarget = JvmTarget.JVM_17

            freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
        }
    }

    extensions.configure<KotlinProjectExtension> {
        jvmToolchain(ProjectConfig.jvmToolchainVersion)
    }
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/ProjectConfig.kt
================================================
package com.infinitepower.newquiz

import org.gradle.api.JavaVersion

object ProjectConfig {
    const val compileSdk = 35

    const val minSdk = 21

    const val targetSdk = 35

    val javaVersionCompatibility = JavaVersion.VERSION_17

    const val jvmTargetVersion = "17"

    const val jvmToolchainVersion = 17
}


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/ProjectExtensions.kt
================================================
package com.infinitepower.newquiz

import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.getByType

val Project.libs
    get(): VersionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")


================================================
FILE: build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/Utils.kt
================================================
package com.infinitepower.newquiz

import org.gradle.api.artifacts.dsl.DependencyHandler

internal fun DependencyHandler.implementation(dependencyNotation: Any) =
    add("implementation", dependencyNotation)

internal fun DependencyHandler.testImplementation(dependencyNotation: Any) =
    add("testImplementation", dependencyNotation)

internal fun DependencyHandler.androidTestImplementation(dependencyNotation: Any) =
    add("androidTestImplementation", dependencyNotation)

internal fun DependencyHandler.ksp(dependencyNotation: Any) =
    add("ksp", dependencyNotation)

internal fun DependencyHandler.kspAndroidTest(dependencyNotation: Any) =
    add("kspAndroidTest", dependencyNotation)

internal fun DependencyHandler.normalImplementation(dependencyNotation: Any) =
    add("normalImplementation", dependencyNotation)

internal fun DependencyHandler.coreLibraryDesugaring(dependencyNotation: Any) =
    add("coreLibraryDesugaring", dependencyNotation)

internal fun DependencyHandler.debugImplementation(dependencyNotation: Any) =
    add("debugImplementation", dependencyNotation)


================================================
FILE: build-logic/gradle.properties
================================================
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true


================================================
FILE: build-logic/settings.gradle.kts
================================================
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }

    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

rootProject.name = "build-logic"
include(":convention")


================================================
FILE: build.gradle.kts
================================================
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask

buildscript {
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath(libs.google.oss.licenses.plugin) {
            exclude(group = "com.google.protobuf")
        }
    }
}

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.jvm) apply false
    alias(libs.plugins.kotlin.serialization) apply false
    alias(libs.plugins.firebase.crashlytics) apply false
    alias(libs.plugins.firebase.perf) apply false
    alias(libs.plugins.gms) apply false
    alias(libs.plugins.hilt) apply false
    alias(libs.plugins.ksp) apply false
    alias(libs.plugins.compose.compiler) apply false
    id("com.github.ben-manes.versions") version "0.51.0"
}

tasks.register("clean", Delete::class) {
    delete(layout.buildDirectory)
}

tasks.withType<DependencyUpdatesTask> {
    rejectVersionIf {
        // Don't allow non-stable versions, unless we are already using one for this dependency
        isNonStable(candidate.version) && !isNonStable(currentVersion)
    }
}

/**
 * Decides if this version is stable or not.
 */
fun isNonStable(version: String): Boolean {
    val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) }
    val regex = "^[0-9,.v-]+(-r)?$".toRegex()
    val isStable = stableKeyword || regex.matches(version)
    return !isStable
}


================================================
FILE: comparison-quiz/.gitignore
================================================
/build

================================================
FILE: comparison-quiz/README.md
================================================
# Comparison quiz

This is the code for the comparison game mode.

![NewQuiz purple light](../pictures/comparison_quiz.jpg)

================================================
FILE: comparison-quiz/build.gradle.kts
================================================
plugins {
    alias(libs.plugins.newquiz.android.library.compose)
    alias(libs.plugins.newquiz.android.hilt)
    alias(libs.plugins.newquiz.android.compose.destinations)
    alias(libs.plugins.newquiz.kotlin.serialization)
    alias(libs.plugins.newquiz.detekt)
}

android {
    namespace = "com.infinitepower.newquiz.comparison_quiz"
}

dependencies {
    implementation(libs.androidx.core.ktx)

    implementation(libs.androidx.lifecycle.livedata.ktx)
    implementation(libs.androidx.lifecycle.runtimeCompose)

    implementation(libs.androidx.compose.ui.tooling)
    implementation(libs.androidx.compose.ui.tooling.preview)
    implementation(libs.androidx.compose.material3)
    implementation(libs.androidx.compose.material3.windowSizeClass)
    implementation(libs.androidx.compose.material.iconsExtended)
    debugImplementation(libs.androidx.compose.ui.testManifest)
    implementation(libs.androidx.constraintlayout.compose)

    androidTestImplementation(libs.androidx.compose.ui.test)
    androidTestImplementation(libs.androidx.test.runner)
    androidTestImplementation(libs.androidx.test.rules)

    implementation(libs.hilt.navigationCompose)

    implementation(libs.kotlinx.serialization.json)

    implementation(libs.coil.kt.compose)
    implementation(libs.coil.kt.svg)

    implementation(libs.ktor.client.core)
    implementation(libs.ktor.client.okhttp)
    implementation(libs.ktor.client.serialization)

    implementation(libs.androidx.work.ktx)
    androidTestImplementation(libs.androidx.work.testing)

    implementation(libs.lottie.compose)

    // Hilt work manager
    implementation(libs.hilt.ext.work)
    ksp(libs.hilt.ext.compiler)

    implementation(projects.core)
    implementation(projects.core.analytics)
    implementation(projects.core.remoteConfig)
    implementation(projects.core.userServices)
    implementation(projects.model)
    implementation(projects.domain)
    implementation(projects.data)
    testImplementation(projects.core.testing)
    androidTestImplementation(projects.core.testing)
}

tasks.withType<Test> {
    useJUnitPlatform()
}

ksp {
    arg("compose-destinations.mode", "destinations")
    arg("compose-destinations.moduleName", "comparison-quiz")
}


================================================
FILE: comparison-quiz/consumer-rules.pro
================================================


================================================
FILE: comparison-quiz/proguard-rules.pro
================================================
# Temporary fix
-dontwarn java.lang.invoke.StringConcatFactory

================================================
FILE: comparison-quiz/src/androidTest/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity
            android:name="androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity"
            android:exported="true"
            tools:node="merge">

            <intent-filter tools:node="removeAll" />
        </activity>

        <activity
            android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
            android:exported="true"
            tools:node="merge">

            <intent-filter tools:node="removeAll" />
        </activity>

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="remove" />
    </application>
</manifest>

================================================
FILE: comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/data/comparison_quiz/FakeComparisonQuizRepositoryImpl.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.data.comparison_quiz

import com.infinitepower.newquiz.domain.repository.comparison_quiz.ComparisonQuizRepository
import com.infinitepower.newquiz.model.FlowResource
import com.infinitepower.newquiz.model.Resource
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizCategory
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizItem
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlin.random.Random

class FakeComparisonQuizRepositoryImpl(
    private val initialQuestions: List<ComparisonQuizItem> = emptyList(),
    private val initialCategories: List<ComparisonQuizCategory> = emptyList()
) : ComparisonQuizRepository {

    private val questions = mutableListOf<ComparisonQuizItem>()

    private val categories = mutableListOf<ComparisonQuizCategory>()

    private val highestPosition = MutableStateFlow(0)

    override fun getCategories(): List<ComparisonQuizCategory> = categories.toList()

    init {
        questions.addAll(initialQuestions)
        categories.addAll(initialCategories)
    }

    override fun getQuestions(
        category: ComparisonQuizCategory,
        size: Int,
        random: Random
    ): Flow<List<ComparisonQuizItem>> = flowOf(questions.take(size))

    override suspend fun getHighestPosition(categoryId: String): Int {
        return highestPosition.first()
    }

    override fun getHighestPositionFlow(categoryId: String): Flow<Int> {
        return highestPosition.map { it }
    }
}

================================================
FILE: comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponentTest.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list.components

import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsNotSelected
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme
import com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
internal class ComparisonModeComponentTest {
    @get:Rule
    val componentRule = createComposeRule()

    @Test
    fun comparisonModeComponent_greater_shouldDisplayTitleAndIcon() {
        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = true,
                    mode = ComparisonMode.GREATER
                )
            }
        }

        // Assert that the title is displayed and has the correct text
        componentRule
            .onNodeWithText("Greater")
            .assertExists()
            .assertIsDisplayed()

        // Assert that the icon is displayed and has the correct content description
        componentRule
            .onNodeWithContentDescription("Icon of Greater")
            .assertExists()
            .assertIsDisplayed()
    }

    @Test
    fun comparisonModeComponent_lesser_shouldDisplayTitleAndIcon() {
        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = true,
                    mode = ComparisonMode.LESSER
                )
            }
        }

        // Assert that the title is displayed and has the correct text
        componentRule
            .onNodeWithText("Lesser")
            .assertExists()
            .assertIsDisplayed()

        // Assert that the icon is displayed and has the correct content description
        componentRule
            .onNodeWithContentDescription("Icon of Lesser")
            .assertExists()
            .assertIsDisplayed()
    }

    @Test
    fun comparisonModeComponent_shouldInvokeOnClick_whenEnabled() {
        var clicked = false

        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = true,
                    enabled = true,
                    mode = ComparisonMode.LESSER,
                    onClick = { clicked = true },
                    modifier = Modifier.testTag("ComparisonModeComponent")
                )
            }
        }

        // Click on the Composable
        componentRule
            .onNodeWithTag("ComparisonModeComponent")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertHasClickAction()
            .performClick()

        // Assert that the onClick callback was invoked
        assertThat(clicked).isTrue()
    }

    @Test
    fun comparisonModeComponent_shouldNotInvokeOnClick_whenNotEnabled() {
        var clicked = false

        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = true,
                    enabled = false,
                    mode = ComparisonMode.LESSER,
                    onClick = { clicked = true },
                    modifier = Modifier.testTag("ComparisonModeComponent")
                )
            }
        }

        // Click on the Composable
        componentRule
            .onNodeWithTag("ComparisonModeComponent")
            .assertIsDisplayed()
            .assertIsNotEnabled()
            .performClick()

        // Assert that the onClick callback was invoked
        assertThat(clicked).isFalse()
    }

    @Test
    fun comparisonModeComponent_shouldBeSelected() {
        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = true,
                    mode = ComparisonMode.LESSER,
                    modifier = Modifier.testTag("ComparisonModeComponent")
                )
            }
        }

        componentRule
            .onNodeWithTag("ComparisonModeComponent")
            .assertIsDisplayed()
            .assertIsSelected()
    }

    @Test
    fun comparisonModeComponent_should_not_beSelected() {
        componentRule.setContent {
            com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                ComparisonModeComponent(
                    selected = false,
                    mode = ComparisonMode.LESSER,
                    modifier = Modifier.testTag("ComparisonModeComponent")
                )
            }
        }

        componentRule
            .onNodeWithTag("ComparisonModeComponent")
            .assertIsDisplayed()
            .assertIsNotSelected()
    }
}


================================================
FILE: comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponentsTest.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list.components

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotSelected
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onLast
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.infinitepower.newquiz.core.testing.utils.setTestContent
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
internal class ComparisonModeComponentsTest {
    @get:Rule
    val componentRule = createComposeRule()

    @Test
    fun comparisonModeComponent_greater_shouldBeSelected() {
        componentRule.setTestContent {
            ComparisonModeComponents(
                modifier = Modifier.fillMaxWidth(),
                selectedMode = ComparisonMode.GREATER
            )
        }

        // Assert that the greater text and icon are displayed and content selected

        componentRule
            .onNodeWithText("Greater")
            .assertExists()
            .assertIsDisplayed()
            .assertIsSelected()

        componentRule
            .onNodeWithContentDescription("Icon of Greater")
            .assertExists()
            .assertIsDisplayed()

        // Assert that the lesser text and icon are displayed and content not selected

        componentRule
            .onNodeWithText("Lesser")
            .assertExists()
            .assertIsDisplayed()
            .assertIsNotSelected()

        componentRule
            .onNodeWithContentDescription("Icon of Lesser")
            .assertExists()
            .assertIsDisplayed()
    }

    @Test
    fun comparisonModeComponent_lesser_shouldBeSelected() {
        componentRule.setTestContent {
            ComparisonModeComponents(
                modifier = Modifier.fillMaxWidth(),
                selectedMode = ComparisonMode.LESSER
            )
        }

        // Assert that the greater text and icon are displayed and content selected

        componentRule
            .onNodeWithText("Greater")
            .assertExists()
            .assertIsDisplayed()
            .assertIsNotSelected()

        componentRule
            .onNodeWithContentDescription("Icon of Greater")
            .assertExists()
            .assertIsDisplayed()

        // Assert that the lesser text and icon are displayed and content not selected

        componentRule
            .onNodeWithText("Lesser")
            .assertExists()
            .assertIsDisplayed()
            .assertIsSelected()

        componentRule
            .onNodeWithContentDescription("Icon of Lesser")
            .assertExists()
            .assertIsDisplayed()
    }

    @Test
    fun row_hasCorrectModifiers() {
        componentRule.setTestContent {
            ComparisonModeComponents(
                modifier = Modifier
                    .fillMaxWidth()
                    .testTag("ComparisonModeComponents"),
                selectedMode = ComparisonMode.GREATER
            )
        }

        componentRule
            .onNodeWithTag("ComparisonModeComponents")
            .onChildren()
            .assertCountEquals(2)

        componentRule
            .onNodeWithTag("ComparisonModeComponents")
            .onChildren()
            .onFirst()
            .assertTextEquals("Greater")
            .assertIsDisplayed()
            .assertIsSelected()

        componentRule
            .onNodeWithTag("ComparisonModeComponents")
            .onChildren()
            .onLast()
            .assertTextEquals("Lesser")
            .assertIsDisplayed()
            .assertIsNotSelected()
    }

    @Test
    fun onModeClick_greater_onClick_when_otherModeIsSelected() {
        var selectedMode by mutableStateOf(ComparisonMode.GREATER)

        componentRule.setTestContent {
            ComparisonModeComponents(
                selectedMode = selectedMode,
                onModeClick = { mode -> selectedMode = mode }
            )
        }

        componentRule
            .onNodeWithText("Greater")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsSelected()

        // Click on the LESSER mode.
        componentRule
            .onNodeWithText("Lesser")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsNotSelected()
            .assertHasClickAction()
            .performClick() // Click on the mode that is not selected.
            .assertIsSelected() // This should select the mode.

        componentRule
            .onNodeWithText("Greater")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsNotSelected()

        // Verify that the onModeClick callback is called with the correct mode.
        assertThat(selectedMode).isNotNull()
        assertThat(selectedMode).isEqualTo(ComparisonMode.LESSER)
    }

    @Test
    fun onModeClick_greater_onClick_when_sameModeIsSelected() {
        var selectedMode by mutableStateOf(ComparisonMode.GREATER)

        componentRule.setTestContent {
            ComparisonModeComponents(
                selectedMode = selectedMode,
                onModeClick = { mode -> selectedMode = mode }
            )
        }

        componentRule
            .onNodeWithText("Lesser")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsNotSelected()

        // Click on the GREATER mode.
        componentRule
            .onNodeWithText("Greater")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsSelected()
            .assertHasClickAction()
            .performClick() // Click on the mode that is already selected.
            .assertIsSelected() // This should not do anything since the mode is already selected.

        componentRule
            .onNodeWithText("Lesser")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertIsNotSelected()

        // Verify that the onModeClick callback is called with the correct mode.
        assertThat(selectedMode).isNotNull()
        assertThat(selectedMode).isEqualTo(ComparisonMode.GREATER)
    }
}


================================================
FILE: comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizScreenTest.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.ui

import androidx.activity.ComponentActivity
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.lifecycle.SavedStateHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.Configuration
import androidx.work.WorkManager
import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
import com.google.common.truth.Truth.assertThat
import com.infinitepower.newquiz.comparison_quiz.core.ComparisonQuizCoreImpl
import com.infinitepower.newquiz.comparison_quiz.data.comparison_quiz.FakeComparisonQuizRepositoryImpl
import com.infinitepower.newquiz.core.analytics.LocalDebugAnalyticsHelper
import com.infinitepower.newquiz.core.game.ComparisonQuizCore
import com.infinitepower.newquiz.core.remote_config.RemoteConfig
import com.infinitepower.newquiz.core.user_services.UserService
import com.infinitepower.newquiz.domain.repository.comparison_quiz.ComparisonQuizRepository
import com.infinitepower.newquiz.domain.repository.home.RecentCategoriesRepository
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizCategory
import com.infinitepower.newquiz.model.NumberFormatType
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizHelperValueState
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizItem
import com.infinitepower.newquiz.model.toUiText
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import io.mockk.every
import io.mockk.mockk
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.net.URI
import javax.inject.Inject

/**
 * Tests for [ComparisonQuizScreen].
 */
@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
@OptIn(
    ExperimentalMaterial3WindowSizeClassApi::class,
    ExperimentalTestApi::class
)
internal class ComparisonQuizScreenTest {
    @get:Rule
    val hiltRule = HiltAndroidRule(this)

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    private lateinit var comparisonQuizRepository: ComparisonQuizRepository

    @Inject lateinit var userService: UserService

    private val remoteConfig = mockk<RemoteConfig>(relaxed = true)
    private val recentCategoriesRepository = mockk<RecentCategoriesRepository>(relaxed = true)

    private lateinit var comparisonQuizCore: ComparisonQuizCore

    private lateinit var viewModel: ComparisonQuizViewModel

    private lateinit var workManager: WorkManager

    private val comparisonMode by lazy { ComparisonMode.GREATER }

    private val category by lazy {
        ComparisonQuizCategory(
            id = "numbers",
            name = "Numbers".toUiText(),
            description = "Numbers description",
            image = "",
            questionDescription = ComparisonQuizCategory.QuestionDescription(
                greater = "Which number is greater?",
                less = "Which number is lesser?",
            ),
            formatType = NumberFormatType.DEFAULT,
            dataSourceAttribution = ComparisonQuizCategory.DataSourceAttribution(
                text = "NewQuiz API",
                logo = ""
            )
        )
    }

    private val firstItemHelperValueState = ComparisonQuizHelperValueState.HIDDEN

    @Before
    fun setUp() {
        hiltRule.inject()

        comparisonQuizRepository = FakeComparisonQuizRepositoryImpl(
            initialQuestions = listOf(
                ComparisonQuizItem(
                    title = "Question 1",
                    value = 1.0,
                    imgUri = URI("")
                ),
                ComparisonQuizItem(
                    title = "Question 2",
                    value = 2.0,
                    imgUri = URI("")
                ),
                ComparisonQuizItem(
                    title = "Question 3",
                    value = 3.0,
                    imgUri = URI("")
                ),
            ),
            initialCategories = listOf(category)
        )

        every {
            remoteConfig.getString("comparison_quiz_first_item_helper_value")
        } returns firstItemHelperValueState.name

        comparisonQuizCore = ComparisonQuizCoreImpl(
            comparisonQuizRepository = comparisonQuizRepository,
            remoteConfig = remoteConfig,
            analyticsHelper = LocalDebugAnalyticsHelper(),
            userService = userService
        )

        val context = InstrumentationRegistry.getInstrumentation().context
        val config = Configuration.Builder()
            .setMinimumLoggingLevel(android.util.Log.DEBUG)
            .setExecutor(SynchronousExecutor())
            .build()

        // Initialize WorkManager for instrumentation tests.
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)

        workManager = WorkManager.getInstance(context)

        viewModel = ComparisonQuizViewModel(
            comparisonQuizCore = comparisonQuizCore,
            savedStateHandle = SavedStateHandle(
                mapOf(
                    ComparisonQuizScreenNavArg::comparisonMode.name to comparisonMode,
                    ComparisonQuizScreenNavArg::category.name to category.toEntity()
                )
            ),
            comparisonQuizRepository = comparisonQuizRepository,
            workManager = workManager,
            recentCategoriesRepository = recentCategoriesRepository,
            userService = userService
        )

        composeTestRule.setContent {
            val windowSizeClass = calculateWindowSizeClass(activity = composeTestRule.activity)

            com.infinitepower.newquiz.core.testing.ui.theme.NewQuizTestTheme {
                com.infinitepower.newquiz.core.testing.utils.setTestDeviceLocale()

                ComparisonQuizScreen(
                    windowSizeClass = windowSizeClass,
                    navigator = EmptyDestinationsNavigator,
                    viewModel = viewModel
                )
            }
        }
    }

    @Test
    fun comparisonQuizScreen_testComponentsDisplayed() {
        val questionDescription = category.getQuestionDescription(comparisonMode)

        composeTestRule.waitUntilAtLeastOneExists(
            matcher = hasText(questionDescription),
            timeoutMillis = 5000
        )

        // Check if the question description is displayed
        composeTestRule
            .onNodeWithText(questionDescription)
            .assertIsDisplayed()

        // Check if the first item is displayed
        composeTestRule
            .onNodeWithText("Question 1")
            .assertIsDisplayed()

        // Check if first item helper text is displayed
        composeTestRule
            .onNodeWithText("1")
            .apply {
                if (firstItemHelperValueState == ComparisonQuizHelperValueState.HIDDEN) {
                    assertDoesNotExist()
                } else {
                    assertIsDisplayed()
                }
            }

        // Check if the second item is displayed
        composeTestRule
            .onNodeWithText("Question 2")
            .assertIsDisplayed()

        // Check if second item helper text is not displayed
        composeTestRule
            .onNodeWithText("2")
            .assertDoesNotExist()

        // Check if data source attribution is displayed
        composeTestRule
            .onNodeWithText("NewQuiz API")
            .assertIsDisplayed()

        // Check if current position is displayed
        composeTestRule
            .onNodeWithText("Position: 1")
            .assertIsDisplayed()

        // Check if highest position is displayed
        composeTestRule
            .onNodeWithText("Highest: 1")
            .assertIsDisplayed()
    }

    @Test
    fun comparisonQuizScreen_testWrongAnswerClick() {
        // Click on the first item (wrong answer)
        // The value of the first item is 1.0
        // The value of the second item is 2.0
        composeTestRule
            .onNodeWithText("Question 1")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertHasClickAction()
            .performClick()
            // When the wrong answer is clicked should end the game
            .assertDoesNotExist()

        // Check if the game is over
        assertThat(viewModel.uiState.value.isGameOver).isTrue()

        // Check if the game over screen is displayed
        composeTestRule
            .onNodeWithText("Game Over")
            .assertIsDisplayed()
    }

    @Test
    fun comparisonQuizScreen_testCorrectAnswerClick() {
        // Click on the second item (correct answer)
        // The value of the first item is 1.0
        // The value of the second item is 2.0
        composeTestRule
            .onNodeWithText("Question 2")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertHasClickAction()
            .performClick()
            // When the correct answer is clicked should not end the game
            .assertIsDisplayed()
            .assertHasClickAction()

        // Check if the game is not over
        assertThat(viewModel.uiState.value.isGameOver).isFalse()

        // Check if the game over screen is not displayed
        composeTestRule
            .onNodeWithText("Game Over")
            .assertDoesNotExist()

        // Now the first item should be the second item
        // and the second item should be a new item
        composeTestRule
            .onNodeWithText("Question 3")
            .assertIsDisplayed()
            .assertHasClickAction()
    }
}

================================================
FILE: comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/ui/components/ComparisonItemTest.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.ui.components

import android.net.Uri
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizHelperValueState
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
internal class ComparisonItemTest {
    @get:Rule
    val componentRule = createComposeRule()

    @Test
    fun comparisonItem_titleAndHelperValueDisplayed() {
        val title = "Item title"
        val helperValue = "Helper value"
        val helperValueState = ComparisonQuizHelperValueState.NORMAL
        var onClickCalled = false

        componentRule.setContent {
            ComparisonItem(
                title = title,
                image = Uri.EMPTY,
                helperValue = helperValue,
                helperContentAlignment = Alignment.BottomEnd,
                helperValueState = helperValueState,
                onClick = { onClickCalled = true },
                modifier = Modifier.testTag("ComparisonItem")
            )
        }

        componentRule
            .onNode(hasText(title) or hasText(helperValue))
            .assertExists()
            .assertIsDisplayed()

        componentRule
            .onNodeWithTag("ComparisonItem")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertHasClickAction()
            // Click on the item
            .performClick()
            // Check that the item is still displayed and enabled after the click
            .assertIsDisplayed()
            .assertIsEnabled()

        assertThat(onClickCalled).isTrue()
    }

    @Test
    fun comparisonItem_titleDisplayed_andHelperValueNotDisplayedWhenStateHidden() {
        val title = "Item title"
        val helperValue = "Helper value"
        val helperValueState = ComparisonQuizHelperValueState.HIDDEN
        var onClickCalled = false

        componentRule.setContent {
            ComparisonItem(
                title = title,
                image = Uri.EMPTY,
                helperValue = helperValue,
                helperContentAlignment = Alignment.BottomEnd,
                helperValueState = helperValueState,
                onClick = { onClickCalled = true },
                modifier = Modifier.testTag("ComparisonItem")
            )
        }

        componentRule
            .onNodeWithText(title)
            .assertExists()
            .assertIsDisplayed()

        componentRule
            .onNodeWithText(helperValue)
            .assertDoesNotExist()

        componentRule
            .onNodeWithTag("ComparisonItem")
            .assertIsDisplayed()
            .assertIsEnabled()
            .assertHasClickAction()
            // Click on the item
            .performClick()
            // Check that the item is still displayed and enabled after the click
            .assertIsDisplayed()
            .assertIsEnabled()

        assertThat(onClickCalled).isTrue()
    }
}

================================================
FILE: comparison-quiz/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>

================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/core/ComparisonQuizCoreImpl.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.core

import android.util.Log
import com.infinitepower.newquiz.core.analytics.AnalyticsEvent
import com.infinitepower.newquiz.core.analytics.AnalyticsHelper
import com.infinitepower.newquiz.core.game.ComparisonQuizCore
import com.infinitepower.newquiz.core.game.ComparisonQuizCore.InitializationData
import com.infinitepower.newquiz.core.game.ComparisonQuizCore.QuizData
import com.infinitepower.newquiz.core.game.GameOverException
import com.infinitepower.newquiz.core.remote_config.RemoteConfig
import com.infinitepower.newquiz.core.remote_config.RemoteConfigValue
import com.infinitepower.newquiz.core.remote_config.get
import com.infinitepower.newquiz.core.user_services.InsufficientDiamondsException
import com.infinitepower.newquiz.core.user_services.UserService
import com.infinitepower.newquiz.data.util.mappers.comparisonquiz.toModel
import com.infinitepower.newquiz.domain.repository.comparison_quiz.ComparisonQuizRepository
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizItem
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizItemEntity
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import javax.inject.Inject

private const val TAG = "ComparisonQuizCoreImpl"

/**
 * Represents the implementation of the [ComparisonQuizCore] interface.
 *
 * @param comparisonQuizRepository The repository for retrieving comparison quiz data.
 */
class ComparisonQuizCoreImpl @Inject constructor(
    private val comparisonQuizRepository: ComparisonQuizRepository,
    private val remoteConfig: RemoteConfig,
    private val analyticsHelper: AnalyticsHelper,
    private val userService: UserService
) : ComparisonQuizCore {
    private val _quizData = MutableStateFlow(QuizData())
    override val quizDataFlow = _quizData.asStateFlow()

    override suspend fun initializeGame(initializationData: InitializationData) {
        val category = initializationData.category
        val questions = initializationData.initialItems
            .map(ComparisonQuizItemEntity::toModel)
            .ifEmpty {
                // If there are no initial items, get the questions from the repository
                comparisonQuizRepository.getQuestions(initializationData.category)
            }

        if (questions.isEmpty()) {
            Log.w(TAG, "No questions found for category ${initializationData.category.id}")
            return endGame()
        }

        val comparisonMode = initializationData.comparisonMode
        val questionDescription = category.getQuestionDescription(comparisonMode)

        val firstItemHelperValue =
            remoteConfig.get(RemoteConfigValue.COMPARISON_QUIZ_FIRST_ITEM_HELPER_VALUE)

        val quizData = QuizData(
            category = category,
            questions = questions,
            comparisonMode = comparisonMode,
            questionDescription = questionDescription,
            firstItemHelperValueState = firstItemHelperValue,
        )

        analyticsHelper.logEvent(
            AnalyticsEvent.ComparisonQuizGameStart(
                category = category.id,
                comparisonMode = comparisonMode.name,
            )
        )

        _quizData.emit(quizData)
        startGame()
    }

    override fun startGame() {
        _quizData.update { currentData ->
            try {
                currentData.getNextQuestion()
            } catch (e: GameOverException) {
                e.printStackTrace()
                return endGame()
            }
        }
    }

    override fun onAnswerClicked(answer: ComparisonQuizItem) {
        Log.d(TAG, "Answer clicked: $answer")

        _quizData.update { currentData ->
            val currentQuestion = currentData.currentQuestion
            val isQuestionCorrect = currentQuestion != null && currentQuestion.isCorrectAnswer(answer)
            Log.d(TAG, "Is question correct: $isQuestionCorrect")

            // If the current question is null or the answer is correct, get the next question
            if (currentQuestion == null || isQuestionCorrect) {
                try {
                    currentData.getNextQuestion()
                } catch (e: GameOverException) {
                    e.printStackTrace()
                    currentData.copy(
                        currentQuestion = null,
                        isGameOver = true,
                        isLastQuestionCorrect = isQuestionCorrect
                    )
                }
            } else {
                currentData.copy(
                    currentQuestion = null,
                    isGameOver = true,
                    isLastQuestionCorrect = false
                )
            }
        }
    }

    override fun endGame() {
        _quizData.update { currentData ->
            currentData.copy(
                currentQuestion = null,
                isGameOver = true
            )
        }
    }

    override val skipCost: UInt
        get() = remoteConfig.get(RemoteConfigValue.COMPARISON_QUIZ_SKIP_COST).toUInt()

    override suspend fun getUserDiamonds(): UInt = userService.getUserDiamonds()

    override suspend fun skip() {
        Log.d(TAG, "Skipping question")

        val userDiamonds = getUserDiamonds()
        val skipCost = skipCost

        // Check if the user has enough diamonds to skip the question
        if (userDiamonds < skipCost) {
            throw InsufficientDiamondsException(
                diamondsNeeded = skipCost,
                diamondsAvailable = userDiamonds
            )
        }

        // Update the user's diamond count
        userService.addRemoveDiamonds(-skipCost.toInt())

        // Update the quiz data to the next question
        _quizData.update { currentData ->
            try {
                currentData.getNextQuestion(skipped = true)
            } catch (e: GameOverException) {
                e.printStackTrace()
                return endGame()
            }
        }
    }
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/core/workers/ComparisonQuizEndGameWorker.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.core.workers

import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.infinitepower.newquiz.core.analytics.AnalyticsEvent
import com.infinitepower.newquiz.core.analytics.AnalyticsHelper
import com.infinitepower.newquiz.core.user_services.UserService
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject

@HiltWorker
class ComparisonQuizEndGameWorker @AssistedInject constructor(
    @Assisted appContext: Context,
    @Assisted workerParams: WorkerParameters,
    private val analyticsHelper: AnalyticsHelper,
    private val userService: UserService,
) : CoroutineWorker(appContext, workerParams) {
    companion object {
        private const val CATEGORY_ID = "category_id"
        private const val COMPARISON_MODE_NAME = "comparison_mode_name"
        private const val END_POSITION = "end_position"
        private const val SKIPPED_ANSWERS = "skipped_answers"

        fun enqueueWork(
            workManager: WorkManager,
            categoryId: String,
            comparisonMode: ComparisonMode,
            endPosition: Int,
            skippedAnswers: Int
        ) {
            val data = workDataOf(
                CATEGORY_ID to categoryId,
                COMPARISON_MODE_NAME to comparisonMode.name,
                END_POSITION to endPosition,
                SKIPPED_ANSWERS to skippedAnswers
            )

            val workRequest = OneTimeWorkRequestBuilder<ComparisonQuizEndGameWorker>()
                .setInputData(data)
                .build()

            workManager.enqueue(workRequest)
        }
    }

    override suspend fun doWork(): Result {
        val categoryId = inputData.getString(CATEGORY_ID) ?: return Result.failure()
        val comparisonModeName = inputData.getString(COMPARISON_MODE_NAME) ?: return Result.failure()
        val endPosition = inputData.getInt(END_POSITION, 0)
        val skippedAnswers = inputData.getInt(SKIPPED_ANSWERS, 0)

        analyticsHelper.logEvent(
            AnalyticsEvent.ComparisonQuizGameEnd(
                category = categoryId,
                comparisonMode = comparisonModeName,
                score = endPosition,
            )
        )

        userService.saveComparisonQuizGame(
            categoryId = categoryId,
            comparisonMode = comparisonModeName,
            endPosition = endPosition.toUInt(),
            skippedAnswers = skippedAnswers.toUInt(),
            generateXp = true
        )

        return Result.success()
    }
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/di/ComparisonQuizModule.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.di

import com.infinitepower.newquiz.comparison_quiz.core.ComparisonQuizCoreImpl
import com.infinitepower.newquiz.core.game.ComparisonQuizCore
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent

@Module
@InstallIn(ViewModelComponent::class)
abstract class ComparisonQuizModule {
    @Binds
    abstract fun bindComparisonQuizCore(impl: ComparisonQuizCoreImpl): ComparisonQuizCore
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreen.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.infinitepower.newquiz.comparison_quiz.destinations.ComparisonQuizScreenDestination
import com.infinitepower.newquiz.comparison_quiz.list.components.ComparisonModeComponents
import com.infinitepower.newquiz.core.analytics.AnalyticsEvent
import com.infinitepower.newquiz.core.analytics.LocalAnalyticsHelper
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.core.theme.spacing
import com.infinitepower.newquiz.core.ui.home.HomeLazyColumn
import com.infinitepower.newquiz.core.ui.home.homeCategoriesItems
import com.infinitepower.newquiz.domain.repository.home.HomeCategories
import com.infinitepower.newquiz.model.NumberFormatType
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizCategory
import com.infinitepower.newquiz.model.toUiText
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.collections.immutable.persistentListOf
import com.infinitepower.newquiz.core.R as CoreR

@Composable
@Destination
fun ComparisonQuizListScreen(
    navigator: DestinationsNavigator,
    viewModel: ComparisonQuizListScreenViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    val analyticsHelper = LocalAnalyticsHelper.current

    ComparisonQuizListScreenImpl(
        uiState = uiState,
        onCategoryClick = { category ->
            analyticsHelper.logEvent(
                AnalyticsEvent.CategoryClicked(
                    game = AnalyticsEvent.Game.COMPARISON_QUIZ,
                    categoryId = category.id,
                    otherData = mapOf(
                        "comparison_mode" to uiState.selectedMode.name.lowercase(),
                    )
                )
            )

            navigator.navigate(
                ComparisonQuizScreenDestination(
                    categoryId = category.id,
                    comparisonMode = uiState.selectedMode
                )
            )
        },
        onSelectMode = { mode ->
            viewModel.onEvent(ComparisonQuizListScreenUiEvent.SelectMode(mode))
        }
    )
}

@Composable
private fun ComparisonQuizListScreenImpl(
    uiState: ComparisonQuizListScreenUiState,
    onCategoryClick: (category: ComparisonQuizCategory) -> Unit,
    onSelectMode: (mode: ComparisonMode) -> Unit
) {
    val spaceMedium = MaterialTheme.spacing.medium

    var seeAllCategories by remember { mutableStateOf(false) }

    HomeLazyColumn {
        item {
            Column {
                Text(
                    text = stringResource(id = CoreR.string.select_a_comparison_mode_for_the_first_item),
                    style = MaterialTheme.typography.bodyMedium
                )
                Spacer(modifier = Modifier.height(spaceMedium))
                ComparisonModeComponents(
                    modifier = Modifier.fillParentMaxWidth(),
                    onModeClick = onSelectMode,
                    selectedMode = uiState.selectedMode
                )
            }
        }

        item {
            Text(
                text = stringResource(id = CoreR.string.categories),
                style = MaterialTheme.typography.bodyMedium
            )
        }

        homeCategoriesItems(
            seeAllCategories = seeAllCategories,
            recentCategories = uiState.homeCategories.recentCategories,
            otherCategories = uiState.homeCategories.otherCategories,
            isInternetAvailable = uiState.internetConnectionAvailable,
            onCategoryClick = onCategoryClick,
            onSeeAllCategoriesClick = { seeAllCategories = !seeAllCategories },
            showConnectionInfo = uiState.showCategoryConnectionInfo
        )
    }
}

@Composable
@PreviewLightDark
private fun ComparisonQuizListScreenPreview() {
    NewQuizTheme {
        Surface {
            ComparisonQuizListScreenImpl(
                uiState = ComparisonQuizListScreenUiState(
                    homeCategories = HomeCategories(
                        recentCategories = persistentListOf(
                            ComparisonQuizCategory(
                                id = "test",
                                description = "Description",
                                name = "Title".toUiText(),
                                image = "",
                                questionDescription = ComparisonQuizCategory.QuestionDescription(
                                    greater = "Greater",
                                    less = "Less"
                                ),
                                formatType = NumberFormatType.DEFAULT
                            )
                        ),
                        otherCategories = persistentListOf()
                    )
                ),
                onCategoryClick = {},
                onSelectMode = {}
            )
        }
    }
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenUiEvent.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list

import androidx.annotation.Keep
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode

interface ComparisonQuizListScreenUiEvent {
    @Keep
    data class SelectMode(
        val mode: ComparisonMode
    ) : ComparisonQuizListScreenUiEvent
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenUiState.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list

import androidx.annotation.Keep
import com.infinitepower.newquiz.domain.repository.home.HomeCategories
import com.infinitepower.newquiz.domain.repository.home.emptyHomeCategories
import com.infinitepower.newquiz.model.category.ShowCategoryConnectionInfo
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonQuizCategory

@Keep
data class ComparisonQuizListScreenUiState(
    val homeCategories: HomeCategories<ComparisonQuizCategory> = emptyHomeCategories(),
    val selectedMode: ComparisonMode = ComparisonMode.GREATER,
    val internetConnectionAvailable: Boolean = true,
    val showCategoryConnectionInfo: ShowCategoryConnectionInfo = ShowCategoryConnectionInfo.NONE
)


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenViewModel.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.infinitepower.newquiz.core.network.NetworkStatusTracker
import com.infinitepower.newquiz.domain.repository.home.RecentCategoriesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import javax.inject.Inject

@HiltViewModel
class ComparisonQuizListScreenViewModel @Inject constructor(
    recentCategoriesRepository: RecentCategoriesRepository,
    networkStatusTracker: NetworkStatusTracker
) : ViewModel() {
    private val _uiState = MutableStateFlow(ComparisonQuizListScreenUiState())

    val uiState = combine(
        _uiState,
        recentCategoriesRepository.getComparisonCategories(
            isInternetAvailable = networkStatusTracker.isCurrentlyConnected()
        ),
        recentCategoriesRepository.getShowCategoryConnectionInfoFlow()
    ) { uiState, recentCategories, showCategoryConnectionInfo ->
        uiState.copy(
            homeCategories = recentCategories,
            internetConnectionAvailable = networkStatusTracker.isCurrentlyConnected(),
            showCategoryConnectionInfo = showCategoryConnectionInfo
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = ComparisonQuizListScreenUiState()
    )

    fun onEvent(event: ComparisonQuizListScreenUiEvent) {
        when (event) {
            is ComparisonQuizListScreenUiEvent.SelectMode -> {
                _uiState.update { currentState ->
                    currentState.copy(selectedMode = event.mode)
                }
            }
        }
    }
}


================================================
FILE: comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponent.kt
================================================
package com.infinitepower.newquiz.comparison_quiz.list.components

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ChevronLeft
import androidx.compose.material.icons.rounded.ChevronRight
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.State
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.infinitepower.newquiz.core.R
import com.infinitepower.newquiz.core.common.compose.preview.BooleanPreviewParameterProvider
import com.infinitepower.newquiz.core.theme.NewQuizTheme
import com.infinitepower.newquiz.core.theme.spacing
import com.infinitepower.newquiz.model.comparison_quiz.ComparisonMode

@Composable
internal fun ComparisonModeComponent(
    modifier: Modifier = Modifier,
    selected: Boolean,
    enabled: Boolean = true,
    mode: ComparisonMode,
    shape: Shape = ComparisonModeDefaults.shape,
    colors: ComparisonModeColors = ComparisonModeDefaults.defaultColors(),
    onClick: () -> Unit = {}
) {
    val title = when (mode) {
        ComparisonMode.GREATER -> stringResource(id = R.str
Download .txt
gitextract_3fcvki05/

├── .github/
│   ├── actions/
│   │   └── get-avd-info/
│   │       └── action.yml
│   └── workflows/
│       ├── android.yml
│       └── android_old.yml
├── .gitignore
├── LICENCE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── lint-baseline.xml
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── AndroidManifest.xml
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── infinitepower/
│           │           └── newquiz/
│           │               ├── NewQuizApp.kt
│           │               ├── core/
│           │               │   ├── navigation/
│           │               │   │   ├── AppNavGraphs.kt
│           │               │   │   ├── CommonNavGraphNavigator.kt
│           │               │   │   └── NavigationItem.kt
│           │               │   └── workers/
│           │               │       └── AppStartLoggingAnalyticsWorker.kt
│           │               ├── initializer/
│           │               │   ├── EnqueueStartWorksInitializer.kt
│           │               │   └── WorkManagerInitializer.kt
│           │               └── ui/
│           │                   ├── components/
│           │                   │   ├── DataCollectionConsentDialog.kt
│           │                   │   └── DiamondsCounter.kt
│           │                   ├── main/
│           │                   │   ├── MainActivity.kt
│           │                   │   ├── MainScreenUiEvent.kt
│           │                   │   ├── MainScreenUiState.kt
│           │                   │   └── MainViewModel.kt
│           │                   └── navigation/
│           │                       ├── CompactNavigationContainer.kt
│           │                       ├── ExpandedNavigationContainer.kt
│           │                       ├── MediumNavigationContainer.kt
│           │                       ├── NavDrawerContent.kt
│           │                       └── NavigationContainer.kt
│           └── res/
│               ├── drawable/
│               │   ├── round_password_24.xml
│               │   ├── round_play_circle_24.xml
│               │   └── round_quiz_24.xml
│               ├── resources.properties
│               ├── values/
│               │   ├── colors.xml
│               │   ├── leak_canary.xml
│               │   ├── splash_screen.xml
│               │   └── strings.xml
│               ├── values-night/
│               │   └── splash_screen.xml
│               └── xml-v25/
│                   └── shortcuts.xml
├── build-logic/
│   ├── .gitignore
│   ├── README.md
│   ├── convention/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               ├── AndroidApplicationComposeConventionPlugin.kt
│   │               ├── AndroidApplicationConventionPlugin.kt
│   │               ├── AndroidApplicationFirebaseConventionPlugin.kt
│   │               ├── AndroidComposeDestinationsConventionPlugin.kt
│   │               ├── AndroidFeatureConventionPlugin.kt
│   │               ├── AndroidHiltConventionPlugin.kt
│   │               ├── AndroidLibraryComposeConventionPlugin.kt
│   │               ├── AndroidLibraryConventionPlugin.kt
│   │               ├── AndroidRoomConventionPlugin.kt
│   │               ├── DetektConventionPlugin.kt
│   │               ├── JvmLibraryConventionPlugin.kt
│   │               ├── KotlinSerializationConventionPlugin.kt
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           ├── AndroidCompose.kt
│   │                           ├── AndroidInstrumentedTests.kt
│   │                           ├── Flavors.kt
│   │                           ├── KotlinAndroid.kt
│   │                           ├── ProjectConfig.kt
│   │                           ├── ProjectExtensions.kt
│   │                           └── Utils.kt
│   ├── gradle.properties
│   └── settings.gradle.kts
├── build.gradle.kts
├── comparison-quiz/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── comparison_quiz/
│       │                       ├── data/
│       │                       │   └── comparison_quiz/
│       │                       │       └── FakeComparisonQuizRepositoryImpl.kt
│       │                       ├── list/
│       │                       │   └── components/
│       │                       │       ├── ComparisonModeComponentTest.kt
│       │                       │       └── ComparisonModeComponentsTest.kt
│       │                       └── ui/
│       │                           ├── ComparisonQuizScreenTest.kt
│       │                           └── components/
│       │                               └── ComparisonItemTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── comparison_quiz/
│       │                       ├── core/
│       │                       │   ├── ComparisonQuizCoreImpl.kt
│       │                       │   └── workers/
│       │                       │       └── ComparisonQuizEndGameWorker.kt
│       │                       ├── di/
│       │                       │   └── ComparisonQuizModule.kt
│       │                       ├── list/
│       │                       │   ├── ComparisonQuizListScreen.kt
│       │                       │   ├── ComparisonQuizListScreenUiEvent.kt
│       │                       │   ├── ComparisonQuizListScreenUiState.kt
│       │                       │   ├── ComparisonQuizListScreenViewModel.kt
│       │                       │   └── components/
│       │                       │       ├── ComparisonModeComponent.kt
│       │                       │       └── ComparisonModeComponents.kt
│       │                       └── ui/
│       │                           ├── AnimationState.kt
│       │                           ├── ComparisonQuizScreen.kt
│       │                           ├── ComparisonQuizUiEvent.kt
│       │                           ├── ComparisonQuizUiState.kt
│       │                           ├── ComparisonQuizViewModel.kt
│       │                           └── components/
│       │                               ├── ComparisonItem.kt
│       │                               ├── ComparisonMidContent.kt
│       │                               ├── GameOverContent.kt
│       │                               └── MiddleCircle.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── comparison_quiz/
│                               └── core/
│                                   └── ComparisonQuizCoreImplTest.kt
├── compose_compiler_config.conf
├── core/
│   ├── .gitignore
│   ├── analytics/
│   │   ├── .gitignore
│   │   ├── LOGGING_ANALYTICS.md
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── analytics/
│   │       │                           └── FossAnalyticsModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── analytics/
│   │       │                           ├── AnalyticsEvent.kt
│   │       │                           ├── AnalyticsHelper.kt
│   │       │                           ├── LocalDebugAnalyticsHelper.kt
│   │       │                           ├── NoOpAnalyticsHelper.kt
│   │       │                           ├── UiHelpers.kt
│   │       │                           └── UserProperty.kt
│   │       └── normal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── analytics/
│   │                                   ├── FirebaseAnalyticsHelper.kt
│   │                                   └── NormalAnalyticsModule.kt
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── database/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   ├── schemas/
│   │   │   └── com.infinitepower.newquiz.core.database.AppDatabase/
│   │   │       ├── 1.json
│   │   │       ├── 2.json
│   │   │       ├── 3.json
│   │   │       ├── 4.json
│   │   │       ├── 5.json
│   │   │       ├── 6.json
│   │   │       └── 7.json
│   │   └── src/
│   │       ├── androidTest/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── database/
│   │       │                           └── dao/
│   │       │                               └── DailyChallengeDaoTest.kt
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── database/
│   │                                   ├── AppDatabase.kt
│   │                                   ├── dao/
│   │                                   │   ├── DailyChallengeDao.kt
│   │                                   │   ├── GameResultDao.kt
│   │                                   │   ├── MazeQuizDao.kt
│   │                                   │   └── SavedMultiChoiceQuestionsDao.kt
│   │                                   ├── di/
│   │                                   │   ├── DaoModule.kt
│   │                                   │   └── DatabaseModule.kt
│   │                                   ├── model/
│   │                                   │   ├── DailyChallengeTaskEntity.kt
│   │                                   │   ├── MazeQuizItemEntity.kt
│   │                                   │   ├── MultiChoiceQuestionEntity.kt
│   │                                   │   └── user/
│   │                                   │       ├── BaseGameResultEntity.kt
│   │                                   │       ├── ComparisonQuizGameResultEntity.kt
│   │                                   │       ├── MultiChoiceGameResultEntity.kt
│   │                                   │       └── WordleGameResultEntity.kt
│   │                                   └── util/
│   │                                       ├── converters/
│   │                                       │   ├── ListConverter.kt
│   │                                       │   ├── LocalDateConverter.kt
│   │                                       │   ├── MathFormulaConverter.kt
│   │                                       │   └── QuestionDifficultyConverter.kt
│   │                                       └── mappers/
│   │                                           └── MultiChoiceQuestionMapper.kt
│   ├── datastore/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── datastore/
│   │       │                           ├── PreferenceRequest.kt
│   │       │                           ├── common/
│   │       │                           │   ├── LocalUserCommon.kt
│   │       │                           │   ├── RecentCategoryDataStoreCommon.kt
│   │       │                           │   └── SettingsCommon.kt
│   │       │                           ├── di/
│   │       │                           │   ├── LocalUserDatastoreModule.kt
│   │       │                           │   ├── RecentCategoriesDatastoreModule.kt
│   │       │                           │   └── SettingsDataStoreModule.kt
│   │       │                           └── manager/
│   │       │                               ├── DataStoreManager.kt
│   │       │                               └── PreferencesDatastoreManager.kt
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── datastore/
│   │       │                           ├── common/
│   │       │                           │   ├── DataAnalyticsCommon.kt
│   │       │                           │   └── TranslationCommon.kt
│   │       │                           └── di/
│   │       │                               └── DataAnalyticsDatastoreModule.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── datastore/
│   │                                   └── manager/
│   │                                       └── PreferencesDatastoreManagerTest.kt
│   ├── proguard-rules.pro
│   ├── remote-config/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── remote_config/
│   │       │                           └── initializer/
│   │       │                               └── RemoteConfigInitializer.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   ├── kotlin/
│   │       │   │   └── com/
│   │       │   │       └── infinitepower/
│   │       │   │           └── newquiz/
│   │       │   │               └── core/
│   │       │   │                   └── remote_config/
│   │       │   │                       ├── LocalDefaultsRemoteConfig.kt
│   │       │   │                       ├── RemoteConfig.kt
│   │       │   │                       ├── RemoteConfigValue.kt
│   │       │   │                       └── RemoteConfigXmlParser.kt
│   │       │   └── res/
│   │       │       └── xml/
│   │       │           └── remote_config_defaults.xml
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── remote_config/
│   │       │                           ├── FirebaseRemoteConfigImpl.kt
│   │       │                           └── initializer/
│   │       │                               └── RemoteConfigInitializer.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── remote_config/
│   │                                   ├── LocalRemoteConfig.kt
│   │                                   └── RemoteConfigTest.kt
│   ├── src/
│   │   ├── androidTest/
│   │   │   ├── AndroidManifest.xml
│   │   │   └── java/
│   │   │       └── com/
│   │   │           └── infinitepower/
│   │   │               └── newquiz/
│   │   │                   └── core/
│   │   │                       └── ui/
│   │   │                           └── components/
│   │   │                               ├── RemainingTimeComponentTest.kt
│   │   │                               ├── category/
│   │   │                               │   ├── CategoryComponentTest.kt
│   │   │                               │   └── CategoryConnectionInfoBadgeTest.kt
│   │   │                               ├── icon/
│   │   │                               │   └── button/
│   │   │                               │       └── BackIconButtonTest.kt
│   │   │                               └── skip_question/
│   │   │                                   └── SkipQuestionDialogTest.kt
│   │   ├── main/
│   │   │   ├── AndroidManifest.xml
│   │   │   ├── java/
│   │   │   │   └── com/
│   │   │   │       └── infinitepower/
│   │   │   │           └── newquiz/
│   │   │   │               └── core/
│   │   │   │                   ├── NumberFormatter.kt
│   │   │   │                   ├── common/
│   │   │   │                   │   ├── BaseApiUrls.kt
│   │   │   │                   │   ├── Common.kt
│   │   │   │                   │   ├── compose/
│   │   │   │                   │   │   └── preview/
│   │   │   │                   │   │       └── BooleanPreviewParameterProvider.kt
│   │   │   │                   │   └── database/
│   │   │   │                   │       └── DatabaseCommon.kt
│   │   │   │                   ├── compose/
│   │   │   │                   │   └── preferences/
│   │   │   │                   │       └── LocalPreferenceEnabledStatus.kt
│   │   │   │                   ├── di/
│   │   │   │                   │   ├── KtorModule.kt
│   │   │   │                   │   └── NetworkStatusModule.kt
│   │   │   │                   ├── game/
│   │   │   │                   │   ├── ComparisonQuizCore.kt
│   │   │   │                   │   ├── GameCore.kt
│   │   │   │                   │   └── SkipGame.kt
│   │   │   │                   ├── math/
│   │   │   │                   │   └── evaluator/
│   │   │   │                   │       ├── Expressions.kt
│   │   │   │                   │       └── internal/
│   │   │   │                   │           ├── Evaluator.kt
│   │   │   │                   │           ├── Expr.kt
│   │   │   │                   │           ├── Function.kt
│   │   │   │                   │           ├── Parser.kt
│   │   │   │                   │           ├── Scanner.kt
│   │   │   │                   │           ├── Token.kt
│   │   │   │                   │           └── TokenType.kt
│   │   │   │                   ├── navigation/
│   │   │   │                   │   └── MazeNavigator.kt
│   │   │   │                   ├── network/
│   │   │   │                   │   ├── NetworkStatusTracker.kt
│   │   │   │                   │   └── NetworkStatusTrackerImpl.kt
│   │   │   │                   ├── theme/
│   │   │   │                   │   ├── ExtendedColor.kt
│   │   │   │                   │   ├── LocalAnimationsEnabled.kt
│   │   │   │                   │   ├── Spacing.kt
│   │   │   │                   │   ├── Theme.kt
│   │   │   │                   │   └── Type.kt
│   │   │   │                   ├── ui/
│   │   │   │                   │   ├── DisabledEmphasisWrappers.kt
│   │   │   │                   │   ├── ObserveAsEvents.kt
│   │   │   │                   │   ├── SnackbarController.kt
│   │   │   │                   │   ├── components/
│   │   │   │                   │   │   ├── AppNameWithLogo.kt
│   │   │   │                   │   │   ├── RemainingTimeComponent.kt
│   │   │   │                   │   │   ├── RoundedPolygonShape.kt
│   │   │   │                   │   │   ├── category/
│   │   │   │                   │   │   │   ├── CategoryBadge.kt
│   │   │   │                   │   │   │   └── CategoryComponent.kt
│   │   │   │                   │   │   ├── icon/
│   │   │   │                   │   │   │   └── button/
│   │   │   │                   │   │   │       └── BackIconButton.kt
│   │   │   │                   │   │   └── skip_question/
│   │   │   │                   │   │       ├── SkipButton.kt
│   │   │   │                   │   │       └── SkipQuestionDialog.kt
│   │   │   │                   │   ├── home/
│   │   │   │                   │   │   ├── ExpandCategoriesButton.kt
│   │   │   │                   │   │   ├── HomeCategoriesItems.kt
│   │   │   │                   │   │   └── HomeLazyColumn.kt
│   │   │   │                   │   ├── home_card/
│   │   │   │                   │   │   ├── HomeListContent.kt
│   │   │   │                   │   │   ├── components/
│   │   │   │                   │   │   │   ├── HomeCardIcon.kt
│   │   │   │                   │   │   │   ├── HomeCardItemContent.kt
│   │   │   │                   │   │   │   ├── HomeGroupTitle.kt
│   │   │   │                   │   │   │   ├── HomeHorizontalItems.kt
│   │   │   │                   │   │   │   ├── HomeLargeCard.kt
│   │   │   │                   │   │   │   ├── HomeMediumCard.kt
│   │   │   │                   │   │   │   └── PlayRandomQuizCard.kt
│   │   │   │                   │   │   └── model/
│   │   │   │                   │   │       └── HomeCardItem.kt
│   │   │   │                   │   ├── icons/
│   │   │   │                   │   │   └── TrophyIcon.kt
│   │   │   │                   │   └── text/
│   │   │   │                   │       └── CompactDecimalText.kt
│   │   │   │                   └── util/
│   │   │   │                       ├── ComposeUtils.kt
│   │   │   │                       ├── PackageUtils.kt
│   │   │   │                       ├── UiTextUtils.kt
│   │   │   │                       ├── UriUtils.kt
│   │   │   │                       ├── android/
│   │   │   │                       │   ├── DrawableUtils.kt
│   │   │   │                       │   └── resources/
│   │   │   │                       │       └── ResourcesUtil.kt
│   │   │   │                       ├── collections/
│   │   │   │                       │   └── Collections.kt
│   │   │   │                       ├── kotlin/
│   │   │   │                       │   ├── BooleanUtils.kt
│   │   │   │                       │   ├── CollectionsUtils.kt
│   │   │   │                       │   ├── Math.kt
│   │   │   │                       │   ├── NumberUtils.kt
│   │   │   │                       │   └── SetUtils.kt
│   │   │   │                       └── model/
│   │   │   │                           └── QuestionDifficultyUtil.kt
│   │   │   └── res/
│   │   │       ├── drawable/
│   │   │       │   ├── github_logo.xml
│   │   │       │   ├── logo_monochromatic.xml
│   │   │       │   ├── round_android_24.xml
│   │   │       │   └── round_flag_circle_24.xml
│   │   │       ├── mipmap-anydpi-v26/
│   │   │       │   ├── ic_launcher.xml
│   │   │       │   └── ic_launcher_round.xml
│   │   │       ├── raw/
│   │   │       │   ├── trophy2.json
│   │   │       │   ├── trophy_winner.json
│   │   │       │   ├── wordle_list.txt
│   │   │       │   ├── wordle_list_es.txt
│   │   │       │   ├── wordle_list_fr.txt
│   │   │       │   └── wordle_list_pt.txt
│   │   │       ├── values/
│   │   │       │   ├── ic_launcher_background.xml
│   │   │       │   ├── strings.xml
│   │   │       │   └── themes.xml
│   │   │       ├── values-de/
│   │   │       │   └── strings.xml
│   │   │       ├── values-es/
│   │   │       │   └── strings.xml
│   │   │       ├── values-et/
│   │   │       │   └── strings.xml
│   │   │       ├── values-fr/
│   │   │       │   └── strings.xml
│   │   │       ├── values-nb-rNO/
│   │   │       │   └── strings.xml
│   │   │       ├── values-night/
│   │   │       │   └── themes.xml
│   │   │       ├── values-pt/
│   │   │       │   └── strings.xml
│   │   │       ├── values-ta/
│   │   │       │   └── strings.xml
│   │   │       └── values-v29/
│   │   │           └── themes.xml
│   │   ├── normal/
│   │   │   ├── AndroidManifest.xml
│   │   │   └── kotlin/
│   │   │       └── com/
│   │   │           └── infinitepower/
│   │   │               └── newquiz/
│   │   │                   └── core/
│   │   │                       └── initializer/
│   │   │                           └── CoreFirebaseInitializer.kt
│   │   └── test/
│   │       └── java/
│   │           └── com/
│   │               └── infinitepower/
│   │                   └── newquiz/
│   │                       └── core/
│   │                           ├── NumberFormatterTest.kt
│   │                           ├── game/
│   │                           │   └── ComparisonQuizDataTest.kt
│   │                           └── util/
│   │                               ├── UiTextTests.kt
│   │                               ├── collections/
│   │                               │   └── CollectionsTest.kt
│   │                               └── kotlin/
│   │                                   ├── BooleanUtilsTest.kt
│   │                                   ├── CollectionsUtilsTest.kt
│   │                                   ├── MathTest.kt
│   │                                   ├── NumberUtilsTest.kt
│   │                                   └── SetUtilsTest.kt
│   ├── testing/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── testing/
│   │       │                           └── di/
│   │       │                               └── TestRemoteConfigModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── testing/
│   │       │                           ├── NewQuizTestRunner.kt
│   │       │                           ├── ScreenshotComparator.kt
│   │       │                           ├── data/
│   │       │                           │   ├── fake/
│   │       │                           │   │   ├── FakeComparisonQuizData.kt
│   │       │                           │   │   └── FakeData.kt
│   │       │                           │   └── repository/
│   │       │                           │       ├── comparison_quiz/
│   │       │                           │       │   └── FakeComparisonQuizRepositoryImpl.kt
│   │       │                           │       ├── multi_choice_quiz/
│   │       │                           │       │   └── TestMultiChoiceQuestionRepositoryImpl.kt
│   │       │                           │       └── numbers/
│   │       │                           │           └── FakeNumberTriviaQuestionApiImpl.kt
│   │       │                           ├── di/
│   │       │                           │   ├── TestDatabaseModule.kt
│   │       │                           │   ├── TestKtorModule.kt
│   │       │                           │   ├── TestRepositoryModule.kt
│   │       │                           │   └── WorkManagerModule.kt
│   │       │                           ├── domain/
│   │       │                           │   ├── FakeDailyChallengeDao.kt
│   │       │                           │   └── FakeGameResultDao.kt
│   │       │                           ├── ui/
│   │       │                           │   └── theme/
│   │       │                           │       └── TestTheme.kt
│   │       │                           └── utils/
│   │       │                               ├── ComposeRule.kt
│   │       │                               ├── LocaleUtils.kt
│   │       │                               └── LogUtils.kt
│   │       └── normal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── testing/
│   │                                   └── di/
│   │                                       ├── RemoteConfigModule.kt
│   │                                       └── TestAnalyticsModule.kt
│   ├── translation/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   ├── consumer-rules.pro
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       ├── androidTestNormal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── translation/
│   │       │                       └── GoogleTranslatorUtilTest.kt
│   │       ├── foss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── NoTranslatorUtil.kt
│   │       │                           └── di/
│   │       │                               └── TranslatorModule.kt
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── TranslatorLanguageSettings.kt
│   │       │                           ├── TranslatorModelState.kt
│   │       │                           └── TranslatorUtil.kt
│   │       ├── normal/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           ├── GoogleTranslatorUtil.kt
│   │       │                           └── di/
│   │       │                               └── GoogleTranslatorModule.kt
│   │       ├── testFoss/
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── core/
│   │       │                       └── translation/
│   │       │                           └── NoTranslatorUtilTest.kt
│   │       └── testNormal/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── core/
│   │                               └── translation/
│   │                                   └── GoogleTranslatorUtilTest.kt
│   └── user-services/
│       ├── .gitignore
│       ├── build.gradle.kts
│       └── src/
│           ├── androidTest/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── core/
│           │                       └── user_services/
│           │                           └── LocalUserServiceImplTest.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── core/
│           │                       └── user_services/
│           │                           ├── DateTimeRangeFormatter.kt
│           │                           ├── GameResultTracker.kt
│           │                           ├── InsufficientDiamondsException.kt
│           │                           ├── LocalUserService.kt
│           │                           ├── LocalUserServiceImpl.kt
│           │                           ├── UserService.kt
│           │                           ├── XpManager.kt
│           │                           ├── data/
│           │                           │   └── xp/
│           │                           │       ├── ComparisonQuizXpGeneratorImpl.kt
│           │                           │       ├── MultiChoiceQuizXpGeneratorImpl.kt
│           │                           │       └── WordleXpGeneratorImpl.kt
│           │                           ├── di/
│           │                           │   ├── UserModule.kt
│           │                           │   └── XpGeneratorsModule.kt
│           │                           ├── domain/
│           │                           │   └── xp/
│           │                           │       ├── ComparisonQuizXpGenerator.kt
│           │                           │       ├── MultiChoiceQuizXpGenerator.kt
│           │                           │       ├── WordleXpGenerator.kt
│           │                           │       └── XpGenerator.kt
│           │                           ├── model/
│           │                           │   └── User.kt
│           │                           └── workers/
│           │                               └── MultiChoiceQuizEndGameWorker.kt
│           └── test/
│               └── kotlin/
│                   └── com/
│                       └── infinitepower/
│                           └── newquiz/
│                               └── core/
│                                   └── user_services/
│                                       ├── DateTimeRangeFormatterTest.kt
│                                       ├── LocalUserServiceImplUnitTest.kt
│                                       ├── data/
│                                       │   └── xp/
│                                       │       ├── ComparisonQuizXpGeneratorImplTest.kt
│                                       │       ├── MultiChoiceQuizXpGeneratorImplTest.kt
│                                       │       └── WordleXpGeneratorImplTest.kt
│                                       └── model/
│                                           └── UserTest.kt
├── data/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── data/
│       │                       ├── daily_challenge/
│       │                       │   └── DailyChallengeRepositoryImplTest.kt
│       │                       ├── repository/
│       │                       │   ├── comparison_quiz/
│       │                       │   │   └── ComparisonQuizRepositoryImplTest.kt
│       │                       │   └── country/
│       │                       │       └── CountryRepositoryImplTest.kt
│       │                       └── worker/
│       │                           ├── daily_challenge/
│       │                           │   └── VerifyDailyChallengeWorkerTest.kt
│       │                           └── maze/
│       │                               ├── CleanMazeQuizWorkerTest.kt
│       │                               └── GenerateMazeQuizWorkerTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── infinitepower/
│       │   │           └── newquiz/
│       │   │               └── data/
│       │   │                   ├── di/
│       │   │                   │   ├── MathModule.kt
│       │   │                   │   └── RepositoryModule.kt
│       │   │                   ├── local/
│       │   │                   │   ├── multi_choice_quiz/
│       │   │                   │   │   └── category/
│       │   │                   │   │       └── MultiChoiceQuestionCategories.kt
│       │   │                   │   └── wordle/
│       │   │                   │       └── WordleCategories.kt
│       │   │                   ├── repository/
│       │   │                   │   ├── UserConfigRepositoryImpl.kt
│       │   │                   │   ├── comparison_quiz/
│       │   │                   │   │   ├── ComparisonQuizApi.kt
│       │   │                   │   │   ├── ComparisonQuizApiImpl.kt
│       │   │                   │   │   └── ComparisonQuizRepositoryImpl.kt
│       │   │                   │   ├── country/
│       │   │                   │   │   ├── CountryEntity.kt
│       │   │                   │   │   └── CountryRepositoryImpl.kt
│       │   │                   │   ├── daily_challenge/
│       │   │                   │   │   ├── DailyChallengeRepositoryImpl.kt
│       │   │                   │   │   └── util/
│       │   │                   │   │       └── DailyChallengeTypeTitleUtil.kt
│       │   │                   │   ├── home/
│       │   │                   │   │   └── RecentCategoriesRepositoryImpl.kt
│       │   │                   │   ├── math_quiz/
│       │   │                   │   │   └── MathQuizCoreRepositoryImpl.kt
│       │   │                   │   ├── maze_quiz/
│       │   │                   │   │   └── MazeQuizRepositoryImpl.kt
│       │   │                   │   ├── multi_choice_quiz/
│       │   │                   │   │   ├── CountryCapitalFlagsQuizRepositoryImpl.kt
│       │   │                   │   │   ├── FlagQuizRepositoryImpl.kt
│       │   │                   │   │   ├── GuessMathSolutionRepositoryImpl.kt
│       │   │                   │   │   ├── LogoQuizRepositoryImpl.kt
│       │   │                   │   │   ├── MultiChoiceQuestionRepositoryImpl.kt
│       │   │                   │   │   ├── dto/
│       │   │                   │   │   │   └── OpenTDBQuestionResponse.kt
│       │   │                   │   │   └── saved_questions/
│       │   │                   │   │       └── SavedMultiChoiceQuestionsRepositoryImpl.kt
│       │   │                   │   ├── numbers/
│       │   │                   │   │   ├── NumberTriviaQuestionApiImpl.kt
│       │   │                   │   │   └── NumberTriviaQuestionRepositoryImpl.kt
│       │   │                   │   └── wordle/
│       │   │                   │       ├── InvalidWordError.kt
│       │   │                   │       └── WordleRepositoryImpl.kt
│       │   │                   ├── util/
│       │   │                   │   ├── mappers/
│       │   │                   │   │   ├── comparisonquiz/
│       │   │                   │   │   │   └── ComparisonQuizMapper.kt
│       │   │                   │   │   ├── daily_challenge/
│       │   │                   │   │   │   └── DailyChallengeTaskMapper.kt
│       │   │                   │   │   └── maze/
│       │   │                   │   │       └── MazeQuizMappers.kt
│       │   │                   │   └── translation/
│       │   │                   │       └── WordleTitleUtil.kt
│       │   │                   └── worker/
│       │   │                       ├── UpdateGlobalEventDataWorker.kt
│       │   │                       ├── daily_challenge/
│       │   │                       │   └── VerifyDailyChallengeWorker.kt
│       │   │                       ├── maze/
│       │   │                       │   ├── CleanMazeQuizWorker.kt
│       │   │                       │   └── GenerateMazeQuizWorker.kt
│       │   │                       └── multichoicequiz/
│       │   │                           └── DownloadMultiChoiceQuestionsWorker.kt
│       │   └── res/
│       │       └── raw/
│       │           └── all_countries.json
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── data/
│                               ├── local/
│                               │   ├── math_quiz/
│                               │   │   └── MathQuizCoreRepositoryImplTest.kt
│                               │   └── wordle/
│                               │       └── WordleCategoriesTest.kt
│                               └── repository/
│                                   ├── comparison_quiz/
│                                   │   ├── ComparisonQuizApiImplTest.kt
│                                   │   └── ComparisonQuizRepositoryImplTest.kt
│                                   ├── country/
│                                   │   ├── CountryRepositoryImplTest.kt
│                                   │   └── TestCountryRepositoryImpl.kt
│                                   ├── daily_challenge/
│                                   │   └── DailyChallengeRepositoryImplTest.kt
│                                   ├── home/
│                                   │   └── RecentCategoriesRepositoryImplTest.kt
│                                   ├── maze_quiz/
│                                   │   └── MazeQuizRepositoryImplTest.kt
│                                   ├── multi_choice_quiz/
│                                   │   ├── CountryCapitalFlagsQuizRepositoryImplTest.kt
│                                   │   └── FlagQuizRepositoryImplTest.kt
│                                   └── wordle/
│                                       └── WordleRepositoryImplTest.kt
├── detekt-compose.yml
├── detekt.yml
├── domain/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── domain/
│       │                       ├── repository/
│       │                       │   ├── CountryRepository.kt
│       │                       │   ├── UserConfigRepository.kt
│       │                       │   ├── comparison_quiz/
│       │                       │   │   └── ComparisonQuizRepository.kt
│       │                       │   ├── daily_challenge/
│       │                       │   │   └── DailyChallengeRepository.kt
│       │                       │   ├── home/
│       │                       │   │   └── RecentCategoriesRepository.kt
│       │                       │   ├── math_quiz/
│       │                       │   │   └── MathQuizCoreRepository.kt
│       │                       │   ├── maze/
│       │                       │   │   └── MazeQuizRepository.kt
│       │                       │   ├── multi_choice_quiz/
│       │                       │   │   ├── CountryCapitalFlagsQuizRepository.kt
│       │                       │   │   ├── FlagQuizRepository.kt
│       │                       │   │   ├── GuessMathSolutionRepository.kt
│       │                       │   │   ├── LogoQuizRepository.kt
│       │                       │   │   ├── MultiChoiceQuestionBaseRepository.kt
│       │                       │   │   ├── MultiChoiceQuestionRepository.kt
│       │                       │   │   └── saved_questions/
│       │                       │   │       └── SavedMultiChoiceQuestionsRepository.kt
│       │                       │   ├── numbers/
│       │                       │   │   ├── NumberTriviaQuestionApi.kt
│       │                       │   │   └── NumberTriviaQuestionRepository.kt
│       │                       │   └── wordle/
│       │                       │       └── WordleRepository.kt
│       │                       └── use_case/
│       │                           └── question/
│       │                               ├── GetRandomMultiChoiceQuestionUseCase.kt
│       │                               └── IsQuestionSavedUseCase.kt
│       └── test/
│           └── kotlin/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── domain/
│                               └── use_case/
│                                   └── question/
│                                       └── IsQuestionSavedUseCaseTest.kt
├── feature/
│   ├── daily-challenge/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── daily_challenge/
│   │                                   ├── DailyChallengeScreen.kt
│   │                                   ├── DailyChallengeScreenNavigator.kt
│   │                                   ├── DailyChallengeScreenUiEvent.kt
│   │                                   ├── DailyChallengeScreenUiState.kt
│   │                                   ├── DailyChallengeScreenViewModel.kt
│   │                                   └── components/
│   │                                       └── DailyChallengeCard.kt
│   ├── maze/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── main/
│   │       │   ├── AndroidManifest.xml
│   │       │   └── kotlin/
│   │       │       └── com/
│   │       │           └── infinitepower/
│   │       │               └── newquiz/
│   │       │                   └── feature/
│   │       │                       └── maze/
│   │       │                           ├── MazeScreen.kt
│   │       │                           ├── MazeScreenUiEvent.kt
│   │       │                           ├── MazeScreenUiState.kt
│   │       │                           ├── MazeScreenViewModel.kt
│   │       │                           ├── categories_info/
│   │       │                           │   ├── MazeCategoriesInfoScreen.kt
│   │       │                           │   ├── MazeCategoriesInfoUiState.kt
│   │       │                           │   └── MazeCategoriesInfoViewModel.kt
│   │       │                           ├── common/
│   │       │                           │   └── MazeCategories.kt
│   │       │                           ├── components/
│   │       │                           │   ├── CategoriesInfoBottomSheet.kt
│   │       │                           │   ├── InvalidCategoriesCard.kt
│   │       │                           │   ├── MazeCompletedCard.kt
│   │       │                           │   ├── MazeItemButton.kt
│   │       │                           │   ├── MazePath.kt
│   │       │                           │   └── ScrollToCurrentQuestionButton.kt
│   │       │                           ├── generate/
│   │       │                           │   ├── GenerateMazeScreen.kt
│   │       │                           │   ├── GenerateMazeScreenUiEvent.kt
│   │       │                           │   ├── GenerateMazeScreenUiState.kt
│   │       │                           │   └── GenerateMazeScreenViewModel.kt
│   │       │                           └── level_results/
│   │       │                               ├── LevelResultsScreen.kt
│   │       │                               ├── LevelResultsScreenUiState.kt
│   │       │                               ├── LevelResultsScreenViewModel.kt
│   │       │                               └── components/
│   │       │                                   ├── LevelCompletedContent.kt
│   │       │                                   └── LevelFailedContent.kt
│   │       └── test/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── maze/
│   │                                   └── MazeScreenUiStateTest.kt
│   ├── profile/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── infinitepower/
│   │                       └── newquiz/
│   │                           └── feature/
│   │                               └── profile/
│   │                                   ├── ProfileScreen.kt
│   │                                   ├── ProfileScreenUiEvent.kt
│   │                                   ├── ProfileScreenUiState.kt
│   │                                   ├── ProfileViewModel.kt
│   │                                   └── components/
│   │                                       ├── GoodDayText.kt
│   │                                       ├── MainUserCard.kt
│   │                                       ├── UserXpAndLevelCard.kt
│   │                                       ├── XpEarnedByDayCard.kt
│   │                                       └── chart/
│   │                                           └── Marker.kt
│   └── settings/
│       ├── .gitignore
│       ├── README.md
│       ├── build.gradle.kts
│       └── src/
│           ├── foss/
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── feature/
│           │                       └── settings/
│           │                           ├── common/
│           │                           │   └── BuildVariant.kt
│           │                           └── screens/
│           │                               └── PreferencesScreen.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── kotlin/
│           │       └── com/
│           │           └── infinitepower/
│           │               └── newquiz/
│           │                   └── feature/
│           │                       └── settings/
│           │                           ├── SettingsScreen.kt
│           │                           ├── components/
│           │                           │   ├── AboutAndHelpButtons.kt
│           │                           │   └── preferences/
│           │                           │       ├── PreferenceGroupHeader.kt
│           │                           │       ├── PreferenceItem.kt
│           │                           │       └── widgets/
│           │                           │           ├── CustomPreferenceWidget.kt
│           │                           │           ├── DropDownPreferenceWidget.kt
│           │                           │           ├── ListPreferenceWidget.kt
│           │                           │           ├── MultiSelectListPreferenceWidget.kt
│           │                           │           ├── NavigationButtonWidget.kt
│           │                           │           ├── SeekBarPreferenceWidget.kt
│           │                           │           ├── SwitchPreferenceWidget.kt
│           │                           │           └── TextPreferenceWidget.kt
│           │                           ├── model/
│           │                           │   ├── Preference.kt
│           │                           │   └── ScreenKey.kt
│           │                           ├── screens/
│           │                           │   ├── PreferenceScreen.kt
│           │                           │   ├── about_and_help/
│           │                           │   │   └── AboutAndHelpScreen.kt
│           │                           │   ├── animations/
│           │                           │   │   └── AnimationsScreen.kt
│           │                           │   ├── general/
│           │                           │   │   ├── GeneralScreen.kt
│           │                           │   │   ├── GeneralScreenUiEvent.kt
│           │                           │   │   ├── GeneralScreenUiState.kt
│           │                           │   │   └── GeneralScreenViewModel.kt
│           │                           │   ├── main/
│           │                           │   │   └── MainScreen.kt
│           │                           │   ├── multi_choice_quiz/
│           │                           │   │   └── MultiChoiceQuizScreen.kt
│           │                           │   └── wordle/
│           │                           │       └── WordleScreen.kt
│           │                           └── util/
│           │                               ├── ShowCategoryConnectionInfoUtils.kt
│           │                               └── datastore/
│           │                                   └── DatastoreUtils.kt
│           └── normal/
│               └── kotlin/
│                   └── com/
│                       └── infinitepower/
│                           └── newquiz/
│                               └── feature/
│                                   └── settings/
│                                       ├── common/
│                                       │   └── BuildVariant.kt
│                                       └── screens/
│                                           ├── PreferencesScreen.kt
│                                           ├── analytics/
│                                           │   └── AnimationsScreen.kt
│                                           └── translation/
│                                               ├── TranslationScreen.kt
│                                               ├── TranslationScreenUiEvent.kt
│                                               ├── TranslationScreenUiState.kt
│                                               └── TranslationScreenViewModel.kt
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lint.xml
├── model/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── model/
│       │                       ├── BaseCategory.kt
│       │                       ├── DataAnalyticsConsentState.kt
│       │                       ├── GameMode.kt
│       │                       ├── GameModeCategory.kt
│       │                       ├── Language.kt
│       │                       ├── NumberFormatType.kt
│       │                       ├── RemainingTime.kt
│       │                       ├── Resource.kt
│       │                       ├── TimestampWithValue.kt
│       │                       ├── UiText.kt
│       │                       ├── XP.kt
│       │                       ├── category/
│       │                       │   └── ShowCategoryConnectionInfo.kt
│       │                       ├── comparison_quiz/
│       │                       │   ├── ComparisonMode.kt
│       │                       │   ├── ComparisonQuizCategory.kt
│       │                       │   ├── ComparisonQuizCategoryEntity.kt
│       │                       │   ├── ComparisonQuizHelperValueState.kt
│       │                       │   ├── ComparisonQuizItem.kt
│       │                       │   ├── ComparisonQuizItemEntity.kt
│       │                       │   └── ComparisonQuizQuestion.kt
│       │                       ├── country/
│       │                       │   ├── Continent.kt
│       │                       │   └── Country.kt
│       │                       ├── daily_challenge/
│       │                       │   └── DailyChallengeTask.kt
│       │                       ├── global_event/
│       │                       │   └── GameEvent.kt
│       │                       ├── math_quiz/
│       │                       │   └── MathFormula.kt
│       │                       ├── maze/
│       │                       │   ├── MazePoint.kt
│       │                       │   └── MazeQuiz.kt
│       │                       ├── multi_choice_quiz/
│       │                       │   ├── MultiChoiceBaseCategory.kt
│       │                       │   ├── MultiChoiceCategory.kt
│       │                       │   ├── MultiChoiceQuestion.kt
│       │                       │   ├── MultiChoiceQuestionStep.kt
│       │                       │   ├── MultiChoiceQuestionType.kt
│       │                       │   ├── QuestionLanguage.kt
│       │                       │   ├── SelectedAnswer.kt
│       │                       │   ├── logo_quiz/
│       │                       │   │   └── LogoQuizBaseItem.kt
│       │                       │   └── saved/
│       │                       │       └── SortSavedQuestionsBy.kt
│       │                       ├── number/
│       │                       │   ├── NumberTriviaQuestion.kt
│       │                       │   └── NumberTriviaQuestionsEntity.kt
│       │                       ├── question/
│       │                       │   └── QuestionDifficulty.kt
│       │                       ├── regional_preferences/
│       │                       │   ├── DistanceUnitType.kt
│       │                       │   ├── RegionalPreferences.kt
│       │                       │   └── TemperatureUnit.kt
│       │                       ├── util/
│       │                       │   ├── base64/
│       │                       │   │   ├── Base64.kt
│       │                       │   │   ├── Base64Encoding.kt
│       │                       │   │   └── Base64Url.kt
│       │                       │   └── serializers/
│       │                       │       └── URISerializer.kt
│       │                       └── wordle/
│       │                           ├── WordleCategory.kt
│       │                           ├── WordleItem.kt
│       │                           ├── WordleQuizType.kt
│       │                           ├── WordleRowItem.kt
│       │                           └── WordleWord.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── infinitepower/
│                       └── newquiz/
│                           └── model/
│                               ├── RemainingTimeTest.kt
│                               ├── category/
│                               │   └── ShowCategoryConnectionInfoTest.kt
│                               ├── comparison_quiz/
│                               │   ├── ComparisonQuizCategoryTest.kt
│                               │   └── ComparisonQuizQuestionTest.kt
│                               ├── daily_challenge/
│                               │   ├── DailyChallengeTaskTest.kt
│                               │   └── DailyChallengeTaskTypeTest.kt
│                               ├── math_quiz/
│                               │   └── maze/
│                               │       ├── MazePointTest.kt
│                               │       └── MazeQuizTest.kt
│                               ├── multi_choice_quiz/
│                               │   └── MultiChoiceQuestionTest.kt
│                               ├── util/
│                               │   └── base64/
│                               │       ├── Base64Test.kt
│                               │       └── Base64UrlTest.kt
│                               └── wordle/
│                                   ├── WordleItemTest.kt
│                                   └── WordleRowItemTest.kt
├── multi-choice-quiz/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── infinitepower/
│       │               └── newquiz/
│       │                   └── multi_choice_quiz/
│       │                       ├── MultiChoiceQuizScreenTest.kt
│       │                       └── components/
│       │                           ├── CardQuestionOptionTest.kt
│       │                           ├── QuizStepViewRowTest.kt
│       │                           └── QuizStepViewTest.kt
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── infinitepower/
│           │           └── newquiz/
│           │               └── multi_choice_quiz/
│           │                   ├── MultiChoiceQuizScreen.kt
│           │                   ├── MultiChoiceQuizScreenUiEvent.kt
│           │                   ├── MultiChoiceQuizScreenUiState.kt
│           │                   ├── MultiChoiceQuizScreenViewModel.kt
│           │                   ├── components/
│           │                   │   ├── CardQuestionAnswer.kt
│           │                   │   ├── MultiChoiceQuizContainer.kt
│           │                   │   ├── QuizStepView.kt
│           │                   │   ├── QuizTopBar.kt
│           │                   │   └── difficulty/
│           │                   │       ├── BaseCardDifficultyContent.kt
│           │                   │       ├── FilledCardDifficulty.kt
│           │                   │       ├── OutlinedCardDifficulty.kt
│           │                   │       └── SelectableDifficultyRow.kt
│           │                   ├── list/
│           │                   │   ├── MultiChoiceQuizListScreen.kt
│           │                   │   ├── MultiChoiceQuizListScreenUiState.kt
│           │                   │   └── MultiChoiceQuizListScreenViewModel.kt
│           │                   ├── results/
│           │                   │   └── MultiChoiceQuizResultsScreen.kt
│           │                   └── saved_questions/
│           │                       ├── SavedMultiChoiceQuestionsScreen.kt
│           │                       ├── SavedMultiChoiceQuestionsScreenNavigator.kt
│           │                       ├── SavedMultiChoiceQuestionsUiEvent.kt
│           │                       ├── SavedMultiChoiceQuestionsUiState.kt
│           │                       ├── SavedMultiChoiceQuestionsViewModel.kt
│           │                       └── components/
│           │                           └── SavedQuestionItem.kt
│           └── res/
│               └── values/
│                   └── strings.xml
├── settings.gradle.kts
└── wordle/
    ├── .gitignore
    ├── README.md
    ├── build.gradle.kts
    ├── consumer-rules.pro
    ├── proguard-rules.pro
    └── src/
        ├── androidTest/
        │   └── java/
        │       └── com/
        │           └── infinitepower/
        │               └── newquiz/
        │                   └── wordle/
        │                       ├── WordleScreenTest.kt
        │                       └── components/
        │                           ├── WordleKeyBoardTest.kt
        │                           └── WordleRowComponentTest.kt
        ├── main/
        │   ├── AndroidManifest.xml
        │   └── java/
        │       └── com/
        │           └── infinitepower/
        │               └── newquiz/
        │                   └── wordle/
        │                       ├── WordleScreen.kt
        │                       ├── WordleScreenUiEvent.kt
        │                       ├── WordleScreenUiState.kt
        │                       ├── WordleScreenViewModel.kt
        │                       ├── components/
        │                       │   ├── InfoDialog.kt
        │                       │   ├── WordleKeyBoard.kt
        │                       │   └── WordleRowComponent.kt
        │                       ├── list/
        │                       │   ├── WordleListScreen.kt
        │                       │   ├── WordleListScreenViewModel.kt
        │                       │   └── WordleListUiState.kt
        │                       └── util/
        │                           ├── InvalidWordErrorUiText.kt
        │                           ├── word/
        │                           │   └── WordUtil.kt
        │                           └── worker/
        │                               └── WordleEndGameWorker.kt
        └── test/
            └── java/
                └── com/
                    └── infinitepower/
                        └── newquiz/
                            └── wordle/
                                └── util/
                                    └── word/
                                        └── WordUtilTest.kt
Condensed preview — 659 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,501K chars).
[
  {
    "path": ".github/actions/get-avd-info/action.yml",
    "chars": 568,
    "preview": "# From: coil-kt/coil\nname: 'Get AVD Info'\ndescription: 'Get the AVD info based on its API level.'\ninputs:\n  api-level:\n "
  },
  {
    "path": ".github/workflows/android.yml",
    "chars": 2235,
    "preview": "name: Android CI\n\non:\n  push:\n    branches: [ \"main\" ]\n    paths-ignore:\n      - '**.md'\n  pull_request:\n    branches: ["
  },
  {
    "path": ".github/workflows/android_old.yml",
    "chars": 3845,
    "preview": "name: Android CI\n\non:\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  checks: write\n  id-token: write\n\nenv:\n  JAVA"
  },
  {
    "path": ".gitignore",
    "chars": 614,
    "preview": ".gradle\n/local.properties\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n\n/app/build\n/app/release"
  },
  {
    "path": "LICENCE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 4639,
    "preview": "# New Quiz\n\n[![Version](https://img.shields.io/badge/Version-1.6.2-blueviolet)](https://github.com/joaomanaia/newquiz/re"
  },
  {
    "path": "app/.gitignore",
    "chars": 66,
    "preview": "/build\ngoogle-services.json\n\n*.apk\n*.aab\n*.dm\noutput-metadata.json"
  },
  {
    "path": "app/build.gradle.kts",
    "chars": 4079,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.application)\n    alias(libs.plugins.newquiz.android.application.compose"
  },
  {
    "path": "app/lint-baseline.xml",
    "chars": 214,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<issues format=\"6\" by=\"lint 7.4.0-alpha09\" type=\"baseline\" client=\"gradle\" depend"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 3971,
    "preview": "# Keep `Companion` object fields of serializable classes.\n# This avoids serializer lookup through `getDeclaredClasses` a"
  },
  {
    "path": "app/src/androidTest/AndroidManifest.xml",
    "chars": 1373,
    "preview": "<manifest\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/andro"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 3352,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/NewQuizApp.kt",
    "chars": 158,
    "preview": "package com.infinitepower.newquiz\n\nimport android.app.Application\nimport dagger.hilt.android.HiltAndroidApp\n\n@HiltAndroi"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/core/navigation/AppNavGraphs.kt",
    "chars": 4795,
    "preview": "package com.infinitepower.newquiz.core.navigation\n\nimport androidx.compose.foundation.layout.padding\nimport androidx.com"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/core/navigation/CommonNavGraphNavigator.kt",
    "chars": 4894,
    "preview": "package com.infinitepower.newquiz.core.navigation\n\nimport androidx.navigation.NavController\nimport com.infinitepower.new"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/core/navigation/NavigationItem.kt",
    "chars": 1591,
    "preview": "package com.infinitepower.newquiz.core.navigation\n\nimport androidx.annotation.Keep\nimport androidx.annotation.StringRes\n"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/core/workers/AppStartLoggingAnalyticsWorker.kt",
    "chars": 1870,
    "preview": "package com.infinitepower.newquiz.core.workers\n\nimport android.content.Context\nimport androidx.hilt.work.HiltWorker\nimpo"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/initializer/EnqueueStartWorksInitializer.kt",
    "chars": 894,
    "preview": "package com.infinitepower.newquiz.initializer\n\nimport android.content.Context\nimport androidx.startup.Initializer\nimport"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/initializer/WorkManagerInitializer.kt",
    "chars": 1507,
    "preview": "package com.infinitepower.newquiz.initializer\n\nimport android.content.Context\nimport android.util.Log\nimport androidx.hi"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/components/DataCollectionConsentDialog.kt",
    "chars": 4707,
    "preview": "package com.infinitepower.newquiz.ui.components\n\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/components/DiamondsCounter.kt",
    "chars": 1290,
    "preview": "package com.infinitepower.newquiz.ui.components\n\nimport androidx.compose.foundation.layout.padding\nimport androidx.compo"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/main/MainActivity.kt",
    "chars": 4565,
    "preview": "package com.infinitepower.newquiz.ui.main\n\nimport android.os.Bundle\nimport androidx.activity.ComponentActivity\nimport an"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/main/MainScreenUiEvent.kt",
    "chars": 223,
    "preview": "package com.infinitepower.newquiz.ui.main\n\nimport androidx.annotation.Keep\n\nsealed interface MainScreenUiEvent {\n    @Ke"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/main/MainScreenUiState.kt",
    "chars": 581,
    "preview": "package com.infinitepower.newquiz.ui.main\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz.core.theme.A"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/main/MainViewModel.kt",
    "chars": 3093,
    "preview": "package com.infinitepower.newquiz.ui.main\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\n"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/navigation/CompactNavigationContainer.kt",
    "chars": 6862,
    "preview": "package com.infinitepower.newquiz.ui.navigation\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/navigation/ExpandedNavigationContainer.kt",
    "chars": 4313,
    "preview": "package com.infinitepower.newquiz.ui.navigation\n\nimport android.content.res.Configuration\nimport androidx.compose.founda"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/navigation/MediumNavigationContainer.kt",
    "chars": 5977,
    "preview": "package com.infinitepower.newquiz.ui.navigation\n\nimport android.content.res.Configuration\nimport androidx.compose.founda"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/navigation/NavDrawerContent.kt",
    "chars": 4920,
    "preview": "package com.infinitepower.newquiz.ui.navigation\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compos"
  },
  {
    "path": "app/src/main/java/com/infinitepower/newquiz/ui/navigation/NavigationContainer.kt",
    "chars": 8352,
    "preview": "package com.infinitepower.newquiz.ui.navigation\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx"
  },
  {
    "path": "app/src/main/res/drawable/round_password_24.xml",
    "chars": 1994,
    "preview": "<vector\n    android:height=\"24dp\"\n    android:tint=\"#000000\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\""
  },
  {
    "path": "app/src/main/res/drawable/round_play_circle_24.xml",
    "chars": 474,
    "preview": "<vector android:height=\"24dp\" android:tint=\"#000000\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    andr"
  },
  {
    "path": "app/src/main/res/drawable/round_quiz_24.xml",
    "chars": 1103,
    "preview": "<vector android:height=\"24dp\" android:tint=\"#000000\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    andr"
  },
  {
    "path": "app/src/main/res/resources.properties",
    "chars": 23,
    "preview": "unqualifiedResLocale=en"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 147,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#FF"
  },
  {
    "path": "app/src/main/res/values/leak_canary.xml",
    "chars": 62,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values/splash_screen.xml",
    "chars": 372,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.NewQuiz.Starting\" parent=\"Theme.SplashScreen\">"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 90,
    "preview": "<resources>\n    <string name=\"app_name\" translatable=\"false\">NewQuiz</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-night/splash_screen.xml",
    "chars": 372,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.NewQuiz.Starting\" parent=\"Theme.SplashScreen\">"
  },
  {
    "path": "app/src/main/res/xml-v25/shortcuts.xml",
    "chars": 1710,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shortcuts xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <short"
  },
  {
    "path": "build-logic/.gitignore",
    "chars": 243,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor."
  },
  {
    "path": "build-logic/README.md",
    "chars": 235,
    "preview": "# Build logic\n\nThe build-logic folder defines project-specific convention plugins, used to keep a single source of truth"
  },
  {
    "path": "build-logic/convention/build.gradle.kts",
    "chars": 2948,
    "preview": "import org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n    `"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt",
    "chars": 541,
    "preview": "import com.android.build.api.dsl.ApplicationExtension\nimport com.infinitepower.newquiz.configureAndroidCompose\nimport or"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt",
    "chars": 1883,
    "preview": "import com.android.build.api.dsl.ApplicationExtension\nimport com.infinitepower.newquiz.NewQuizFlavor\nimport com.infinite"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt",
    "chars": 1014,
    "preview": "import com.infinitepower.newquiz.implementation\nimport com.infinitepower.newquiz.libs\nimport com.infinitepower.newquiz.n"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidComposeDestinationsConventionPlugin.kt",
    "chars": 1091,
    "preview": "import com.google.devtools.ksp.gradle.KspExtension\nimport com.infinitepower.newquiz.implementation\nimport com.infinitepo"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt",
    "chars": 1527,
    "preview": "import com.infinitepower.newquiz.debugImplementation\nimport com.infinitepower.newquiz.implementation\nimport com.infinite"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt",
    "chars": 1044,
    "preview": "import com.infinitepower.newquiz.androidTestImplementation\nimport com.infinitepower.newquiz.implementation\nimport com.in"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt",
    "chars": 564,
    "preview": "import com.android.build.api.dsl.LibraryExtension\nimport com.infinitepower.newquiz.configureAndroidCompose\nimport org.gr"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt",
    "chars": 3447,
    "preview": "import com.android.build.api.dsl.LibraryExtension\nimport com.android.build.api.variant.LibraryAndroidComponentsExtension"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt",
    "chars": 1634,
    "preview": "import com.google.devtools.ksp.gradle.KspExtension\nimport com.infinitepower.newquiz.implementation\nimport com.infinitepo"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt",
    "chars": 1455,
    "preview": "import com.infinitepower.newquiz.libs\nimport io.gitlab.arturbosch.detekt.Detekt\nimport org.gradle.api.Plugin\nimport org."
  },
  {
    "path": "build-logic/convention/src/main/kotlin/JvmLibraryConventionPlugin.kt",
    "chars": 1441,
    "preview": "import com.infinitepower.newquiz.configureKotlinJvm\nimport com.infinitepower.newquiz.libs\nimport com.infinitepower.newqu"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/KotlinSerializationConventionPlugin.kt",
    "chars": 511,
    "preview": "import com.infinitepower.newquiz.implementation\nimport com.infinitepower.newquiz.libs\nimport org.gradle.api.Plugin\nimpor"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/AndroidCompose.kt",
    "chars": 2034,
    "preview": "package com.infinitepower.newquiz\n\nimport com.android.build.api.dsl.CommonExtension\nimport org.gradle.api.Project\nimport"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/AndroidInstrumentedTests.kt",
    "chars": 447,
    "preview": "package com.infinitepower.newquiz\n\nimport com.android.build.api.variant.LibraryAndroidComponentsExtension\nimport org.gra"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/Flavors.kt",
    "chars": 1523,
    "preview": "package com.infinitepower.newquiz\n\nimport com.android.build.api.dsl.ApplicationExtension\nimport com.android.build.api.ds"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/KotlinAndroid.kt",
    "chars": 2175,
    "preview": "package com.infinitepower.newquiz\n\nimport com.android.build.api.dsl.CommonExtension\nimport org.gradle.api.Project\nimport"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/ProjectConfig.kt",
    "chars": 320,
    "preview": "package com.infinitepower.newquiz\n\nimport org.gradle.api.JavaVersion\n\nobject ProjectConfig {\n    const val compileSdk = "
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/ProjectExtensions.kt",
    "chars": 317,
    "preview": "package com.infinitepower.newquiz\n\nimport org.gradle.api.Project\nimport org.gradle.api.artifacts.VersionCatalog\nimport o"
  },
  {
    "path": "build-logic/convention/src/main/kotlin/com/infinitepower/newquiz/Utils.kt",
    "chars": 1093,
    "preview": "package com.infinitepower.newquiz\n\nimport org.gradle.api.artifacts.dsl.DependencyHandler\n\ninternal fun DependencyHandler"
  },
  {
    "path": "build-logic/gradle.properties",
    "chars": 83,
    "preview": "org.gradle.parallel=true\norg.gradle.caching=true\norg.gradle.configureondemand=true\n"
  },
  {
    "path": "build-logic/settings.gradle.kts",
    "chars": 277,
    "preview": "dependencyResolutionManagement {\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    versionCatalogs {"
  },
  {
    "path": "build.gradle.kts",
    "chars": 1446,
    "preview": "import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask\n\nbuildscript {\n    repositories {\n        googl"
  },
  {
    "path": "comparison-quiz/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "comparison-quiz/README.md",
    "chars": 123,
    "preview": "# Comparison quiz\n\nThis is the code for the comparison game mode.\n\n![NewQuiz purple light](../pictures/comparison_quiz.j"
  },
  {
    "path": "comparison-quiz/build.gradle.kts",
    "chars": 2223,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library.compose)\n    alias(libs.plugins.newquiz.android.hilt)\n    alias"
  },
  {
    "path": "comparison-quiz/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "comparison-quiz/proguard-rules.pro",
    "chars": 62,
    "preview": "# Temporary fix\n-dontwarn java.lang.invoke.StringConcatFactory"
  },
  {
    "path": "comparison-quiz/src/androidTest/AndroidManifest.xml",
    "chars": 916,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"h"
  },
  {
    "path": "comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/data/comparison_quiz/FakeComparisonQuizRepositoryImpl.kt",
    "chars": 1705,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.data.comparison_quiz\n\nimport com.infinitepower.newquiz.domain.reposito"
  },
  {
    "path": "comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponentTest.kt",
    "chars": 6262,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list.components\n\nimport androidx.compose.ui.Modifier\nimport androidx.c"
  },
  {
    "path": "comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponentsTest.kt",
    "chars": 7136,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list.components\n\nimport androidx.compose.foundation.layout.fillMaxWidt"
  },
  {
    "path": "comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizScreenTest.kt",
    "chars": 10367,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\nimport androidx.activity.ComponentActivity\nimport androidx.compose"
  },
  {
    "path": "comparison-quiz/src/androidTest/java/com/infinitepower/newquiz/comparison_quiz/ui/components/ComparisonItemTest.kt",
    "chars": 3610,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui.components\n\nimport android.net.Uri\nimport androidx.compose.ui.Align"
  },
  {
    "path": "comparison-quiz/src/main/AndroidManifest.xml",
    "chars": 121,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</manifest"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/core/ComparisonQuizCoreImpl.kt",
    "chars": 6048,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.core\n\nimport android.util.Log\nimport com.infinitepower.newquiz.core.an"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/core/workers/ComparisonQuizEndGameWorker.kt",
    "chars": 2797,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.core.workers\n\nimport android.content.Context\nimport androidx.hilt.work"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/di/ComparisonQuizModule.kt",
    "chars": 508,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.di\n\nimport com.infinitepower.newquiz.comparison_quiz.core.ComparisonQu"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreen.kt",
    "chars": 5813,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list\n\nimport androidx.compose.foundation.layout.Column\nimport androidx"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenUiEvent.kt",
    "chars": 315,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenUiState.kt",
    "chars": 812,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/ComparisonQuizListScreenViewModel.kt",
    "chars": 1889,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.vi"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponent.kt",
    "chars": 8602,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list.components\n\nimport androidx.compose.animation.animateColor\nimport"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/list/components/ComparisonModeComponents.kt",
    "chars": 1891,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.list.components\n\nimport androidx.compose.foundation.layout.Arrangement"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/AnimationState.kt",
    "chars": 953,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\n/**\n * Represents the state of the animation in the comparison qui"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizScreen.kt",
    "chars": 20925,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\nimport androidx.annotation.Keep\nimport androidx.compose.animation."
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizUiEvent.kt",
    "chars": 474,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz.m"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizUiState.kt",
    "chars": 1201,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz.m"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/ComparisonQuizViewModel.kt",
    "chars": 7818,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui\n\nimport android.util.Log\nimport androidx.lifecycle.SavedStateHandle"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/components/ComparisonItem.kt",
    "chars": 6094,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui.components\n\nimport android.net.Uri\nimport androidx.compose.animatio"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/components/ComparisonMidContent.kt",
    "chars": 3967,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui.components\n\nimport androidx.compose.foundation.layout.Arrangement\ni"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/components/GameOverContent.kt",
    "chars": 6271,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui.components\n\nimport androidx.compose.foundation.layout.Box\nimport an"
  },
  {
    "path": "comparison-quiz/src/main/java/com/infinitepower/newquiz/comparison_quiz/ui/components/MiddleCircle.kt",
    "chars": 5438,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.ui.components\n\nimport androidx.compose.animation.AnimatedContent\nimpor"
  },
  {
    "path": "comparison-quiz/src/test/java/com/infinitepower/newquiz/comparison_quiz/core/ComparisonQuizCoreImplTest.kt",
    "chars": 19687,
    "preview": "package com.infinitepower.newquiz.comparison_quiz.core\n\nimport androidx.datastore.core.DataStore\nimport androidx.datasto"
  },
  {
    "path": "compose_compiler_config.conf",
    "chars": 209,
    "preview": "// Consider LocalDateTime stable\njava.time.LocalDateTime\n// Consider my datalayer and all submodules stable\ncom.infinite"
  },
  {
    "path": "core/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "core/analytics/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "core/analytics/LOGGING_ANALYTICS.md",
    "chars": 9879,
    "preview": "# Overview\n\nThis document describes the logging analytics events and parameters, collected by the application. \nThe even"
  },
  {
    "path": "core/analytics/README.md",
    "chars": 465,
    "preview": "# Analytics Module (:core:analytics)\n\nThe Analytics module provides a way to track user interactions with the applicatio"
  },
  {
    "path": "core/analytics/build.gradle.kts",
    "chars": 580,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library.compose)\n    alias(libs.plugins.newquiz.android.hilt)\n    alias"
  },
  {
    "path": "core/analytics/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "core/analytics/proguard-rules.pro",
    "chars": 750,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "core/analytics/src/foss/kotlin/com/infinitepower/newquiz/core/analytics/FossAnalyticsModule.kt",
    "chars": 352,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport dagger.Binds\nimport dagger.Module\nimport dagger.hilt.InstallIn\n"
  },
  {
    "path": "core/analytics/src/main/AndroidManifest.xml",
    "chars": 51,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest />"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/AnalyticsEvent.kt",
    "chars": 6271,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz.model"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/AnalyticsHelper.kt",
    "chars": 801,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport kotlinx.coroutines.flow.Flow\n\n/**\n * Interface for logging anal"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/LocalDebugAnalyticsHelper.kt",
    "chars": 1266,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport android.util.Log\nimport kotlinx.coroutines.flow.Flow\nimport kot"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/NoOpAnalyticsHelper.kt",
    "chars": 754,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport kotlinx.coroutines.flow.Flow\nimport kotlinx.coroutines.flow.emp"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/UiHelpers.kt",
    "chars": 289,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport androidx.compose.runtime.staticCompositionLocalOf\n\n/**\n * A loc"
  },
  {
    "path": "core/analytics/src/main/kotlin/com/infinitepower/newquiz/core/analytics/UserProperty.kt",
    "chars": 493,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport androidx.annotation.Size\n\nsealed class UserProperty(\n    @Size("
  },
  {
    "path": "core/analytics/src/normal/kotlin/com/infinitepower/newquiz/core/analytics/FirebaseAnalyticsHelper.kt",
    "chars": 4217,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport com.google.firebase.analytics.FirebaseAnalytics\nimport com.goog"
  },
  {
    "path": "core/analytics/src/normal/kotlin/com/infinitepower/newquiz/core/analytics/NormalAnalyticsModule.kt",
    "chars": 1157,
    "preview": "package com.infinitepower.newquiz.core.analytics\n\nimport com.google.firebase.analytics.FirebaseAnalytics\nimport com.goog"
  },
  {
    "path": "core/build.gradle.kts",
    "chars": 1893,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library.compose)\n    alias(libs.plugins.newquiz.android.hilt)\n    alias"
  },
  {
    "path": "core/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "core/database/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "core/database/build.gradle.kts",
    "chars": 463,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library)\n    alias(libs.plugins.newquiz.android.room)\n    alias(libs.pl"
  },
  {
    "path": "core/database/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "core/database/proguard-rules.pro",
    "chars": 750,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/1.json",
    "chars": 7461,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"2b5755fa1bcc6adc57c9ab82bd83f2e3\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/2.json",
    "chars": 9569,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 2,\n    \"identityHash\": \"fcd9b57e8faa1a7b07c05b842276b5cf\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/3.json",
    "chars": 8493,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 3,\n    \"identityHash\": \"de2a8eef760db8b584b478e1043749db\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/4.json",
    "chars": 9278,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 4,\n    \"identityHash\": \"ca501a93f18f0b24e9772858b9dd5ee8\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/5.json",
    "chars": 14772,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 5,\n    \"identityHash\": \"4e64a492cda5cf6ef8b21c3c9599482a\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/6.json",
    "chars": 13772,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 6,\n    \"identityHash\": \"3a23ffe1cbbd7ba6cecdcd8e2261c827\",\n    \"e"
  },
  {
    "path": "core/database/schemas/com.infinitepower.newquiz.core.database.AppDatabase/7.json",
    "chars": 15879,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 7,\n    \"identityHash\": \"d699dae423a5b36ad66302c323af52db\",\n    \"e"
  },
  {
    "path": "core/database/src/androidTest/AndroidManifest.xml",
    "chars": 361,
    "preview": "<manifest\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/andro"
  },
  {
    "path": "core/database/src/androidTest/kotlin/com/infinitepower/newquiz/core/database/dao/DailyChallengeDaoTest.kt",
    "chars": 3739,
    "preview": "package com.infinitepower.newquiz.core.database.dao\n\nimport android.content.Context\nimport androidx.room.Room\nimport and"
  },
  {
    "path": "core/database/src/main/AndroidManifest.xml",
    "chars": 51,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest />"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/AppDatabase.kt",
    "chars": 3168,
    "preview": "package com.infinitepower.newquiz.core.database\n\nimport android.annotation.SuppressLint\nimport androidx.room.AutoMigrati"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/dao/DailyChallengeDao.kt",
    "chars": 1927,
    "preview": "package com.infinitepower.newquiz.core.database.dao\n\nimport androidx.room.Dao\nimport androidx.room.Insert\nimport android"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/dao/GameResultDao.kt",
    "chars": 3161,
    "preview": "package com.infinitepower.newquiz.core.database.dao\n\nimport androidx.annotation.Keep\nimport androidx.room.ColumnInfo\nimp"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/dao/MazeQuizDao.kt",
    "chars": 1382,
    "preview": "package com.infinitepower.newquiz.core.database.dao\n\nimport androidx.room.Dao\nimport androidx.room.Delete\nimport android"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/dao/SavedMultiChoiceQuestionsDao.kt",
    "chars": 1379,
    "preview": "package com.infinitepower.newquiz.core.database.dao\n\nimport androidx.room.Dao\nimport androidx.room.Delete\nimport android"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/di/DaoModule.kt",
    "chars": 1122,
    "preview": "package com.infinitepower.newquiz.core.database.di\n\nimport com.infinitepower.newquiz.core.database.AppDatabase\nimport co"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/di/DatabaseModule.kt",
    "chars": 715,
    "preview": "package com.infinitepower.newquiz.core.database.di\n\nimport android.content.Context\nimport androidx.room.Room\nimport com."
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/DailyChallengeTaskEntity.kt",
    "chars": 499,
    "preview": "package com.infinitepower.newquiz.core.database.model\n\nimport androidx.annotation.Keep\nimport androidx.room.Entity\nimpor"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/MazeQuizItemEntity.kt",
    "chars": 1565,
    "preview": "package com.infinitepower.newquiz.core.database.model\n\nimport androidx.annotation.Keep\nimport androidx.room.Embedded\nimp"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/MultiChoiceQuestionEntity.kt",
    "chars": 2153,
    "preview": "package com.infinitepower.newquiz.core.database.model\n\nimport androidx.annotation.Keep\nimport androidx.room.ColumnInfo\ni"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/user/BaseGameResultEntity.kt",
    "chars": 160,
    "preview": "package com.infinitepower.newquiz.core.database.model.user\n\ninterface BaseGameResultEntity {\n    val gameId: Int\n    val"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/user/ComparisonQuizGameResultEntity.kt",
    "chars": 828,
    "preview": "package com.infinitepower.newquiz.core.database.model.user\n\nimport androidx.annotation.Keep\nimport androidx.room.ColumnI"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/user/MultiChoiceGameResultEntity.kt",
    "chars": 849,
    "preview": "package com.infinitepower.newquiz.core.database.model.user\n\nimport androidx.annotation.Keep\nimport androidx.room.ColumnI"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/model/user/WordleGameResultEntity.kt",
    "chars": 787,
    "preview": "package com.infinitepower.newquiz.core.database.model.user\n\nimport androidx.annotation.Keep\nimport androidx.room.ColumnI"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/util/converters/ListConverter.kt",
    "chars": 415,
    "preview": "package com.infinitepower.newquiz.core.database.util.converters\n\nimport androidx.room.TypeConverter\nimport kotlinx.seria"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/util/converters/LocalDateConverter.kt",
    "chars": 349,
    "preview": "package com.infinitepower.newquiz.core.database.util.converters\n\nimport androidx.room.TypeConverter\nimport kotlinx.datet"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/util/converters/MathFormulaConverter.kt",
    "chars": 405,
    "preview": "package com.infinitepower.newquiz.core.database.util.converters\n\nimport androidx.room.TypeConverter\nimport com.infinitep"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/util/converters/QuestionDifficultyConverter.kt",
    "chars": 409,
    "preview": "package com.infinitepower.newquiz.core.database.util.converters\n\nimport androidx.room.TypeConverter\nimport com.infinitep"
  },
  {
    "path": "core/database/src/main/kotlin/com/infinitepower/newquiz/core/database/util/mappers/MultiChoiceQuestionMapper.kt",
    "chars": 1358,
    "preview": "package com.infinitepower.newquiz.core.database.util.mappers\n\nimport com.infinitepower.newquiz.core.database.model.Multi"
  },
  {
    "path": "core/datastore/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "core/datastore/build.gradle.kts",
    "chars": 349,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library)\n    alias(libs.plugins.newquiz.android.hilt)\n    alias(libs.pl"
  },
  {
    "path": "core/datastore/consumer-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "core/datastore/proguard-rules.pro",
    "chars": 750,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "core/datastore/src/main/AndroidManifest.xml",
    "chars": 52,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest />\n"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/PreferenceRequest.kt",
    "chars": 198,
    "preview": "package com.infinitepower.newquiz.core.datastore\n\nimport androidx.datastore.preferences.core.Preferences\n\nopen class Pre"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/common/LocalUserCommon.kt",
    "chars": 1113,
    "preview": "package com.infinitepower.newquiz.core.datastore.common\n\nimport android.content.Context\nimport androidx.datastore.core.D"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/common/RecentCategoryDataStoreCommon.kt",
    "chars": 857,
    "preview": "package com.infinitepower.newquiz.core.datastore.common\n\nimport android.content.Context\nimport androidx.datastore.core.D"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/common/SettingsCommon.kt",
    "chars": 4369,
    "preview": "package com.infinitepower.newquiz.core.datastore.common\n\nimport android.content.Context\nimport androidx.annotation.Keep\n"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/di/LocalUserDatastoreModule.kt",
    "chars": 1338,
    "preview": "package com.infinitepower.newquiz.core.datastore.di\n\nimport android.content.Context\nimport androidx.datastore.core.DataS"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/di/RecentCategoriesDatastoreModule.kt",
    "chars": 1404,
    "preview": "package com.infinitepower.newquiz.core.datastore.di\n\nimport android.content.Context\nimport androidx.datastore.core.DataS"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/di/SettingsDataStoreModule.kt",
    "chars": 1320,
    "preview": "package com.infinitepower.newquiz.core.datastore.di\n\nimport android.content.Context\nimport androidx.datastore.core.DataS"
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/manager/DataStoreManager.kt",
    "chars": 615,
    "preview": "package com.infinitepower.newquiz.core.datastore.manager\n\nimport androidx.datastore.preferences.core.Preferences\nimport "
  },
  {
    "path": "core/datastore/src/main/kotlin/com/infinitepower/newquiz/core/datastore/manager/PreferencesDatastoreManager.kt",
    "chars": 1383,
    "preview": "package com.infinitepower.newquiz.core.datastore.manager\n\nimport androidx.datastore.core.DataStore\nimport androidx.datas"
  },
  {
    "path": "core/datastore/src/normal/kotlin/com/infinitepower/newquiz/core/datastore/common/DataAnalyticsCommon.kt",
    "chars": 1282,
    "preview": "package com.infinitepower.newquiz.core.datastore.common\n\nimport android.content.Context\nimport androidx.datastore.core.D"
  },
  {
    "path": "core/datastore/src/normal/kotlin/com/infinitepower/newquiz/core/datastore/common/TranslationCommon.kt",
    "chars": 1327,
    "preview": "package com.infinitepower.newquiz.core.datastore.common\n\nimport androidx.datastore.preferences.core.booleanPreferencesKe"
  },
  {
    "path": "core/datastore/src/normal/kotlin/com/infinitepower/newquiz/core/datastore/di/DataAnalyticsDatastoreModule.kt",
    "chars": 1378,
    "preview": "package com.infinitepower.newquiz.core.datastore.di\n\nimport android.content.Context\nimport androidx.datastore.core.DataS"
  },
  {
    "path": "core/datastore/src/test/kotlin/com/infinitepower/newquiz/core/datastore/manager/PreferencesDatastoreManagerTest.kt",
    "chars": 3675,
    "preview": "package com.infinitepower.newquiz.core.datastore.manager\n\nimport androidx.datastore.core.DataStore\nimport androidx.datas"
  },
  {
    "path": "core/proguard-rules.pro",
    "chars": 46,
    "preview": "-dontwarn java.lang.invoke.StringConcatFactory"
  },
  {
    "path": "core/remote-config/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "core/remote-config/README.md",
    "chars": 45,
    "preview": "# Remote Config Module (:core:remote_config)\n"
  },
  {
    "path": "core/remote-config/build.gradle.kts",
    "chars": 525,
    "preview": "plugins {\n    alias(libs.plugins.newquiz.android.library)\n    alias(libs.plugins.newquiz.android.hilt)\n    alias(libs.pl"
  },
  {
    "path": "core/remote-config/src/foss/kotlin/com/infinitepower/newquiz/core/remote_config/initializer/RemoteConfigInitializer.kt",
    "chars": 1187,
    "preview": "package com.infinitepower.newquiz.core.remote_config.initializer\n\nimport android.content.Context\nimport android.util.Log"
  },
  {
    "path": "core/remote-config/src/main/AndroidManifest.xml",
    "chars": 641,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "core/remote-config/src/main/kotlin/com/infinitepower/newquiz/core/remote_config/LocalDefaultsRemoteConfig.kt",
    "chars": 1102,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport android.content.Context\n\nclass NoValueForRemoteConfigKeyExc"
  },
  {
    "path": "core/remote-config/src/main/kotlin/com/infinitepower/newquiz/core/remote_config/RemoteConfig.kt",
    "chars": 2269,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport kotlinx.serialization.Serializable\nimport kotlinx.serializa"
  },
  {
    "path": "core/remote-config/src/main/kotlin/com/infinitepower/newquiz/core/remote_config/RemoteConfigValue.kt",
    "chars": 2230,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport com.infinitepower.newquiz.model.category.ShowCategoryConnec"
  },
  {
    "path": "core/remote-config/src/main/kotlin/com/infinitepower/newquiz/core/remote_config/RemoteConfigXmlParser.kt",
    "chars": 2783,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport android.content.Context\nimport android.content.res.XmlResou"
  },
  {
    "path": "core/remote-config/src/main/res/xml/remote_config_defaults.xml",
    "chars": 33018,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<defaults>\n  <entry>\n    <key>flag_base_url</key>\n    <value>local</value>\n  </en"
  },
  {
    "path": "core/remote-config/src/normal/kotlin/com/infinitepower/newquiz/core/remote_config/FirebaseRemoteConfigImpl.kt",
    "chars": 928,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport com.google.firebase.remoteconfig.FirebaseRemoteConfig\nimpor"
  },
  {
    "path": "core/remote-config/src/normal/kotlin/com/infinitepower/newquiz/core/remote_config/initializer/RemoteConfigInitializer.kt",
    "chars": 1574,
    "preview": "package com.infinitepower.newquiz.core.remote_config.initializer\n\nimport android.content.Context\nimport android.util.Log"
  },
  {
    "path": "core/remote-config/src/test/kotlin/com/infinitepower/newquiz/core/remote_config/LocalRemoteConfig.kt",
    "chars": 810,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\n/**\n * A [RemoteConfig] implementation that uses a map of remote c"
  },
  {
    "path": "core/remote-config/src/test/kotlin/com/infinitepower/newquiz/core/remote_config/RemoteConfigTest.kt",
    "chars": 2833,
    "preview": "package com.infinitepower.newquiz.core.remote_config\n\nimport com.google.common.truth.Truth.assertThat\nimport kotlinx.ser"
  },
  {
    "path": "core/src/androidTest/AndroidManifest.xml",
    "chars": 361,
    "preview": "<manifest\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/andro"
  },
  {
    "path": "core/src/androidTest/java/com/infinitepower/newquiz/core/ui/components/RemainingTimeComponentTest.kt",
    "chars": 2606,
    "preview": "package com.infinitepower.newquiz.core.ui.components\n\nimport androidx.compose.ui.semantics.ProgressBarRangeInfo\nimport a"
  },
  {
    "path": "core/src/androidTest/java/com/infinitepower/newquiz/core/ui/components/category/CategoryComponentTest.kt",
    "chars": 2987,
    "preview": "package com.infinitepower.newquiz.core.ui.components.category\n\nimport androidx.compose.ui.Modifier\nimport androidx.compo"
  },
  {
    "path": "core/src/androidTest/java/com/infinitepower/newquiz/core/ui/components/category/CategoryConnectionInfoBadgeTest.kt",
    "chars": 2751,
    "preview": "package com.infinitepower.newquiz.core.ui.components.category\n\nimport androidx.compose.ui.Modifier\nimport androidx.compo"
  },
  {
    "path": "core/src/androidTest/java/com/infinitepower/newquiz/core/ui/components/icon/button/BackIconButtonTest.kt",
    "chars": 2142,
    "preview": "package com.infinitepower.newquiz.core.ui.components.icon.button\n\nimport androidx.compose.ui.Modifier\nimport androidx.co"
  },
  {
    "path": "core/src/androidTest/java/com/infinitepower/newquiz/core/ui/components/skip_question/SkipQuestionDialogTest.kt",
    "chars": 3238,
    "preview": "package com.infinitepower.newquiz.core.ui.components.skip_question\n\nimport androidx.compose.material3.ExperimentalMateri"
  },
  {
    "path": "core/src/main/AndroidManifest.xml",
    "chars": 344,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/NumberFormatter.kt",
    "chars": 14103,
    "preview": "package com.infinitepower.newquiz.core\n\nimport android.icu.util.LocaleData\nimport android.icu.util.ULocale\nimport androi"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/common/BaseApiUrls.kt",
    "chars": 126,
    "preview": "package com.infinitepower.newquiz.core.common\n\nobject BaseApiUrls {\n    const val NEWQUIZ = \"https://newquiz-app.vercel."
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/common/Common.kt",
    "chars": 237,
    "preview": "package com.infinitepower.newquiz.core.common\n\nconst val DEFAULT_USER_PHOTO = \"https://firebasestorage.googleapis.com/v0"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/common/compose/preview/BooleanPreviewParameterProvider.kt",
    "chars": 292,
    "preview": "package com.infinitepower.newquiz.core.common.compose.preview\n\nimport androidx.compose.ui.tooling.preview.PreviewParamet"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/common/database/DatabaseCommon.kt",
    "chars": 674,
    "preview": "package com.infinitepower.newquiz.core.common.database\n\nobject DatabaseCommon {\n    object UserCollection {\n        cons"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/compose/preferences/LocalPreferenceEnabledStatus.kt",
    "chars": 359,
    "preview": "package com.infinitepower.newquiz.core.compose.preferences\n\nimport androidx.compose.runtime.ProvidableCompositionLocal\ni"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/di/KtorModule.kt",
    "chars": 431,
    "preview": "package com.infinitepower.newquiz.core.di\n\nimport dagger.Module\nimport dagger.Provides\nimport dagger.hilt.InstallIn\nimpo"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/di/NetworkStatusModule.kt",
    "chars": 526,
    "preview": "package com.infinitepower.newquiz.core.di\n\nimport com.infinitepower.newquiz.core.network.NetworkStatusTracker\nimport com"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/game/ComparisonQuizCore.kt",
    "chars": 5766,
    "preview": "package com.infinitepower.newquiz.core.game\n\nimport androidx.annotation.Keep\nimport com.infinitepower.newquiz.model.comp"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/game/GameCore.kt",
    "chars": 1038,
    "preview": "package com.infinitepower.newquiz.core.game\n\nimport kotlinx.coroutines.flow.StateFlow\n\nclass GameOverException(\n    over"
  },
  {
    "path": "core/src/main/java/com/infinitepower/newquiz/core/game/SkipGame.kt",
    "chars": 156,
    "preview": "package com.infinitepower.newquiz.core.game\n\ninterface SkipGame {\n    val skipCost: UInt\n\n    suspend fun getUserDiamond"
  }
]

// ... and 459 more files (download for full content)

About this extraction

This page contains the full source code of the joaomanaia/newquiz GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 659 files (2.2 MB), approximately 613.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!