Commit Graph

9 Commits

Author SHA1 Message Date
Adrian Kuta
7d38facda5 fix: Correct timer behavior and display
This commit addresses issues with the question timer in `QuizScreen`.

Key changes:

- **QuizScreenViewModel:**
    - Initialize `_remainingTimeSeconds` to `0` instead of `-1` to prevent premature timer display.
    - Start timer only if `timerJob` is `null` (not already running) and it's the first question.
    - Set `timerJob` to `null` when it's cancelled (on choice selection, moving to next question, or finishing the quiz).
    - If a question has no time limit (null or <= 0 seconds), set `_remainingTimeSeconds` to `0` and do not start the `timerJob`.
    - When the timer finishes and no choice was selected, set `_selectedChoiceIndex` to `-1` (indicating time ran out) and ensure `timerJob` is nullified.
- **QuizScreen:**
    - Conditionally display the `TimerBar` only if `selectedChoiceIndex` is `null` (no choice made yet) AND `timerState.totalTimeSeconds` is greater than `0` (meaning there's a valid timer for the current question). This prevents showing a timer when a question has no time limit.
2025-09-04 17:59:36 +02:00
Adrian Kuta
d2fce7e7b9 feat: Implement question timer and navigation between questions
This commit introduces a timer for each question in the `QuizScreen` and enables navigation to the next question upon answering or when the timer expires.

Key changes:

- **UI Layer (`ui:quiz` module):**
    - **QuizScreen.kt:**
        - Refactored `QuizScreen` to use `LazyColumn` for better performance and to support animated item changes.
        - Implemented a "Continue" button that appears after a choice is selected, allowing the user to proceed to the next question.
        - The `Choices` layout was changed from `LazyVerticalGrid` to `FlowRow` for more flexible item arrangement.
        - Added a loading state (`CircularProgressIndicator`) while quiz data is being fetched.
        - Question images are now clipped with rounded corners.
        - `ScreenUiState` (formerly `QuizUiState`) now holds `selectedChoiceIndex` directly instead of a separate `AnswerUiState`.
        - The `onContinue` callback is passed to the `QuizScreen` to handle advancing to the next question.
        - Added `animateContentSize` to the main `LazyColumn` for smoother transitions.
    - **QuizScreenViewModel.kt:**
        - Introduced `QuizUiState` (sealed interface with `Loading` and `Success` states) to represent the state of quiz data fetching.
        - Introduced `ScreenUiState` (sealed interface with `Loading` and `Success` states) to represent the overall screen state, including the current question, selected answer, and timer.
        - Implemented timer logic:
            - A countdown timer starts for each question.
            - The timer is cancelled when an answer is selected.
            - `_remainingTimeSeconds` now defaults to -1 to indicate the timer hasn't started for the current question yet.
        - Implemented `onContinue()` function to:
            - Advance to the `_currentQuestionIndex`.
            - Reset `_selectedChoiceIndex`.
            - Start the timer for the new question.
        - The initial quiz fetch now populates the `quiz` StateFlow.
        - The timer starts automatically when the first question of a successfully loaded quiz is ready.
        - `TimerState` data class was created to encapsulate timer-related information.
2025-09-04 17:51:18 +02:00
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
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
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