Commit Graph

11 Commits

Author SHA1 Message Date
Adrian Kuta
41fd729271 feat: Display "Continue" button after answer selection and hide timer
This commit modifies the `QuizScreen` to show a "Continue" button once an answer is selected for the current question. The timer bar is hidden when an answer is chosen.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - In `QuizScreen.kt`:
        - Conditionally display either the `TimerBar` or a `FilledTonalButton` with the text "Continue" based on whether `uiState.answer` is null.
        - The "Continue" button is styled with a grey background and black text.
    - Added a new string resource `continue_text` in `ui/quiz/src/main/res/values/strings.xml`.
2025-09-04 14:09:59 +02:00
Adrian Kuta
f0bd963d2d feat: Implement question timer and update toolbar UI
This commit introduces a timer for questions in the `QuizScreen` and updates the toolbar to display the current question number out of the total.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - In `QuizScreen.kt`:
        - Added a `TimerBar` composable to visually represent the remaining time for a question. This bar animates its width and displays the remaining seconds.
        - Updated the `Toolbar` composable to display the current question index and total number of questions (e.g., "1/10").
        - Passed `currentQuestionIndex`, `totalQuestions`, `totalTimeSeconds`, and `remainingTimeSeconds` from `QuizUiState` to the respective composables.
        - Updated previews to reflect new `QuizUiState` properties.
        - Used `RoundedCornerShape(percent = 50)` for more consistent rounded corners in the `Toolbar`.
    - In `QuizScreenViewModel.kt`:
        - Added `_remainingTimeSeconds` MutableStateFlow to track the countdown.
        - Modified `QuizUiState` to include `currentQuestionIndex`, `totalQuestions`, `totalTimeSeconds`, and `remainingTimeSeconds`.
        - Implemented `startCountdown()` logic to decrease `_remainingTimeSeconds` every second.
        - The timer is started when the ViewModel is initialized and for each new question.
        - When a choice is selected, the timer is cancelled.
        - If the timer runs out before a choice is selected, `_selectedChoiceIndex` is set to -1 to indicate a timeout.
        - The `uiState` flow now combines `getQuizUseCase()`, `_selectedChoiceIndex`, and `_remainingTimeSeconds` to derive the `QuizUiState`.
- **Design System (`core:designsystem` module):**
    - Added `Purple` color definition in `Color.kt` for use in the `TimerBar`.
    - Reordered color definitions alphabetically.
2025-09-04 13:56:33 +02:00
Adrian Kuta
710dedb0cc refactor: Format code with spotless
This commit applies automated code formatting using Spotless across multiple modules. The changes primarily involve adjustments to trailing commas, spacing, and import statements to ensure consistency with the project's coding style.

Key changes include:

- **Kotlin Files:**
    - Added trailing commas to multi-line parameter lists, argument lists, and collection literals in various Kotlin files across `app`, `core:designsystem`, `core:network`, `domain`, and `model:data` modules.
    - Standardized spacing around operators and keywords.
    - Optimized import statements in test files (`ExampleUnitTest.kt`, `ExampleInstrumentedTest.kt`).
- **XML Files:**
    - Reformatted XML attributes in drawable vector files (`ic_*.xml`) within the `core:designsystem` module for better readability.
- **JSON Files:**
    - Reformatted `sample_quiz.json` in `core:network` test resources for consistent structure.
- **Detekt Configuration:**
    - Updated `detekt.yml` files in `app` and `core:designsystem` to adjust ignored annotations lists, ensuring proper spacing (e.g., `['Composable']` to `[ 'Composable' ]`).
2025-09-03 23:46:09 +02:00
Adrian Kuta
7568abb775 feat: Implement interactive quiz screen with answer revealed state
This commit enhances the `QuizScreen` to be interactive, allowing users to select choices and view revealed answers. It also introduces HTML parsing for question text and adds new design elements like icons and colors.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - `QuizScreen`:
        - Now takes an `onSelect` callback to handle choice selection.
        - `Choices` composable updated to display choices in a `LazyVerticalGrid` and handles click events.
        - Introduced `ChoiceItem` which branches into `ChoiceItemDefault` (for selectable choices) and `ChoiceItemRevealed` (for displaying correct/incorrect answers).
        - `ChoiceItemDefault` displays choices with background colors and icons based on their index.
        - `ChoiceItemRevealed` displays choices with background colors indicating correctness (green for correct, red for incorrect selected, pink for incorrect unselected) and appropriate icons (tick for correct, cross for wrong).
        - `QuestionContent` now parses HTML in the question text using `HtmlCompat` and a new `toAnnotatedString` extension.
        - Image loading in `QuestionContent` uses `ContentScale.FillWidth` and `heightIn(min = 200.dp)`.
        - Added a new preview `QuizScreenRevealedAnswerPreview` to showcase the revealed answer state.
    - `QuizScreenViewModel`:
        - Now manages `_selectedChoiceIndex` to track the user's answer.
        - `uiState` is now a combination of the fetched quiz and the `_selectedChoiceIndex`, producing `QuizUiState` which includes an `AnswerUiState`.
        - `AnswerUiState` holds the `selectedChoiceIndex`.
        - Implemented `onChoiceSelected(index: Int)` to update the selected choice.
- **Design System (`core:designsystem` module):**
    - Added `TextUtils.kt` with a `Spanned.toAnnotatedString()` extension function to convert HTML formatted text (from `HtmlCompat`) into Jetpack Compose `AnnotatedString`.
    - Added new color definitions: `Pink`, `Red`, `Red2`, `Blue2`, `Yellow3`, `Green`, `Green2`.
    - Added a `contrastiveTo(color: Color)` utility function to determine a contrasting text color (black or white) for a given background color.
    - Added new vector drawables for choice shapes and correctness indicators:
        - `ic_circle.xml`
        - `ic_correct.xml`
        - `ic_diamond.xml`
        - `ic_square.xml`
        - `ic_triangle.xml`
        - `ic_wrong.xml`
    - Added Detekt configuration file (`config/detekt/detekt.yml`) for the design system module.
- **Domain Layer (`domain` module):**
    - `Question.image` is now nullable (`String?`).
    - `Choice.correct` is now non-nullable (`Boolean`).
- **Network Layer (`core:network` module):**
    - `ChoiceDto.correct` is now non-nullable (`Boolean`) to align with the domain model.
- **Project Configuration:**
    - Added `.editorconfig` with Kotlin specific trailing comma settings.
    - Minor reordering of dependencies in `gradle/libs.versions.toml`.
2025-09-03 23:45:29 +02:00
Adrian Kuta
45550ecf76 feat: Enhance QuizScreen UI and introduce core design system module
This commit significantly revamps the `QuizScreen` UI to display question details including image and text, and introduces a new `core:designsystem` module to centralize theme, colors, typography, and drawable resources.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - Updated `QuizScreen.kt`:
        - Implemented a background image for the screen.
        - Added a `Toolbar` composable to display question progress and type.
        - Created `QuestionContent` composable to show the question image (using Coil for image loading) and text.
        - Added a placeholder `Choices` composable (currently an empty `LazyVerticalGrid`).
        - Applied `fillMaxSize()` to the main `QuizScreen` modifier.
        - Included a `@Preview` for `QuizScreen` with sample data.
    - Modified `QuizScreenViewModel.kt` to update `QuizUiState` with the first `Question` from the fetched quiz.
    - Added a `quiz` string resource in `strings.xml`.
    - Added dependencies for Coil (compose and okhttp) in `ui/quiz/build.gradle.kts`.
- **Core Design System (`core:designsystem` module):**
    - Created a new Android library module `core:designsystem`.
    - Moved `Color.kt`, `Theme.kt`, and `Type.kt` from `app/src/main/java/dev/adriankuta/kahootquiz/ui/theme` to this new module.
    - Added a new `Grey` color to `Color.kt`.
    - Added `bg_image.webp` and `ic_type.xml` drawable resources.
    - Configured the module with `kahootquiz.android.library.compose` plugin.
- **App Module (`app` module):**
    - Updated `MainActivity.kt` to import `KahootQuizTheme` from the new `core.designsystem` package.
    - Added `implementation(projects.core.designsystem)` dependency in `app/build.gradle.kts`.
- **Domain Layer (`domain` module):**
    - Made several fields in `Question.kt` and `Choice.kt` nullable and provided default null values to accommodate potential missing data from the API.
    - Specifically, `Question.image` is now non-nullable (`String`).
- **Build System:**
    - Added `coilCompose` and `coilNetworkOkhttp` versions to `gradle/libs.versions.toml`.
    - Included `:core:designsystem` in `settings.gradle.kts`.
2025-09-03 21:57:18 +02:00
GitHub Actions Bot
57313de1d7 feat: Display Quiz ID in QuizScreen and integrate with navigation
This commit updates the `QuizScreen` to display the ID of the fetched quiz and connects the `QuizScreen` composable to the navigation graph.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - In `QuizScreen.kt`:
        - Modified the `QuizScreen` composable to display the `quiz.id.value` from the `QuizUiState` within a `Column` and `Text` element.
    - In `navigation/QuizNavigation.kt`:
        - Updated the `quizScreen` navigation extension to call the `QuizScreen()` composable.
2025-09-03 13:15:45 +02:00
GitHub Actions Bot
1270ad93d9 feat: Implement QuizScreen and basic navigation structure
This commit introduces the `QuizScreen` composable, its associated `QuizScreenViewModel`, and sets up the basic navigation graph for the application.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - Added `QuizScreen.kt` with a basic composable structure.
    - Implemented `QuizScreenViewModel.kt` which fetches quiz data using `GetQuizUseCase` and exposes it via `QuizUiState`.
    - Created `QuizUiState` data class to hold the quiz data for the UI.
    - Added `navigation/QuizNavigation.kt` to define the `QuizRoute` and `quizScreen` navigation extension.
    - Updated `ui/quiz/build.gradle.kts` to include dependencies for Hilt navigation and Timber.
- **App Module (`app` module):**
    - Created `KahootQuizApp.kt` which sets up the main `Scaffold` and includes the navigation graph.
    - Added `KahootQuizNavGraph.kt` to define the `NavHost` and integrate the `quizScreen`.
    - Modified `MainActivity.kt` to call the new `KahootQuizApp` composable, removing the previous direct use case call and UI.
- **Data Layer (`model:data` module):**
    - Updated `QuizMapper.kt` to convert `time` from `Long?` to `Duration?` (using `milliseconds`) when mapping `QuestionDto` to the domain `Question` model.
2025-09-03 13:08:57 +02:00
GitHub Actions Bot
fd0678c1fd feat: Expand domain models and implement full DTO to domain mapping
This commit significantly expands the domain models to fully represent the quiz structure and implements the complete mapping logic in `QuizMapper` to convert `QuizResponseDto` and its nested DTOs to their corresponding domain models.

Key changes:

- **Domain Layer (`domain` module):**
    - Introduced a `QuizId` value class for type safety.
    - Added comprehensive domain models for all aspects of a quiz, including:
        - `Quiz`: Updated to include all fields from the DTO.
        - `Question`, `Choice`, `Video`, `ImageMetadata`, `MediaItem`, `ChoiceRange`: For question details.
        - `CoverMetadata`, `ExtractedColor`, `Crop`, `Point`: For cover image information.
        - `ContentTags`: For curriculum and generated codes.
        - `Metadata`, `Access`, `FeaturedListMembership`, `LastEdit`, `VersionMetadata`: For quiz metadata.
        - `LanguageInfo`, `Channel`: Common reusable models.
    - Organized domain models into separate files for better maintainability (e.g., `Question.kt`, `CoverMetadata.kt`).
    - Added a placeholder `QuestionModels.kt` to indicate that models were moved.
- **Data Layer (`model:data` module):**
    - Implemented a complete `toDomainModel()` extension function in `QuizMapper.kt` to map all fields from `QuizResponseDto` and its nested DTOs (like `CoverMetadataDto`, `QuestionDto`, etc.) to the new domain models.
    - This includes mapping for lists and nullable fields.
- **App Module (`app` module):**
    - Updated `MainActivity` to access `quizId.value` due to `QuizId` being a value class.
- **Network Layer (`core:network` module):**
    - Changed `QuizResponseDto.uuid` to be non-nullable (`String`) as it's essential for mapping to `QuizId`.
    - Removed `QuizResponse.kt` as DTOs were previously split into individual files.
2025-09-03 12:45:53 +02:00
GitHub Actions Bot
293b7f75b9 feat: Implement data layer and basic quiz fetching logic
This commit introduces the data layer, including the `QuizRepository` and its implementation, and integrates it with the domain layer's `GetQuizUseCase`. It also sets up Hilt for dependency injection in the app module and makes preliminary UI changes to display fetched quiz data.

Key changes include:

- **Data Layer (`model:data` module):**
    - Added `QuizRepositoryImpl` which implements `QuizRepository` from the domain layer.
    - Implemented `getQuiz()` in `QuizRepositoryImpl` to fetch quiz data from `QuizApi` and map it to the domain `Quiz` model using `QuizMapper`.
    - Created `QuizMapper` to convert `QuizResponseDto` to the domain `Quiz` model.
    - Added `RepositoryModule` for Hilt to provide `QuizRepository` bindings.
- **Domain Layer (`domain` module):**
    - Created `Quiz` domain model.
    - Defined `QuizRepository` interface.
    - Implemented `GetQuizUseCase` to interact with `QuizRepository`.
- **App Module (`app` module):**
    - Added `MyApplication` class annotated with `@HiltAndroidApp`.
    - Updated `AndroidManifest.xml` to use `MyApplication` and add internet permission.
    - In `MainActivity`:
        - Injected `GetQuizUseCase`.
        - Used `LaunchedEffect` to call the use case and update a mutable state `quizId`.
        - Modified the `Greeting` composable to display the fetched `quizId`.
    - Added dependency on the `domain` module in `app/build.gradle.kts`.
- **Network Layer (`core:network` module):**
    - Moved DTOs from `core.network.model` package to `core.network.models`.
    - Made `NetworkModule` internal.
    - Removed unused `QuizService` interface and `QuizServiceImpl` class.
- **Testing (`core:network` test):**
    - Updated import path for `QuizResponseDto` in `QuizResponseDtoParsingTest`.
2025-09-02 22:29:15 +02:00
GitHub Actions Bot
f12ac0826e feat: Implement initial project structure and network layer
This commit introduces the foundational structure of the Kahoot Quiz application and implements the core network layer.

Key changes include:
- Added new Gradle modules: `core:network`, `domain`, `model:data`, and `ui:quiz`.
- Configured Detekt for static code analysis in the new modules.
- Implemented Retrofit and Gson for network communication and JSON parsing.
- Defined DTOs for the Kahoot quiz API response, splitting them into logical files (QuizResponseDto, CommonDtos, CoverDtos, QuestionDtos, MetadataDtos, ContentTagsDto) for better organization.
- Created `QuizApi` interface with a GET request for fetching quiz data.
- Added `QuizService` interface and its initial implementation `QuizServiceImpl`.
- Set up Hilt for dependency injection in the network module, providing Retrofit and QuizApi instances.
- Included a `sample_quiz.json` file for testing and development.
- Added unit tests (`QuizResponseDtoParsingTest`) to verify the correct parsing of the sample JSON into DTOs.
- Updated `.gitignore` to exclude additional generated files and IDE specific folders.
- Modified `settings.gradle.kts` to include the new modules.
- Updated `app/build.gradle.kts` to include dependencies on the new `ui:quiz` and `model:data` modules and removed unused dependencies.
2025-09-02 22:14:50 +02:00
GitHub Actions Bot
d4ec154b8c Initial commit 2025-09-02 15:43:25 +02:00