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.
This commit is contained in:
GitHub Actions Bot
2025-09-03 12:45:53 +02:00
parent 293b7f75b9
commit fd0678c1fd
27 changed files with 417 additions and 18 deletions

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
// Access settings
data class Access(
val groupRead: List<String>?,
val folderGroupIds: List<String>?,
val features: List<String>?
)

View File

@@ -0,0 +1,5 @@
package dev.adriankuta.kahootquiz.domain.models
// Minimal channel info
data class Channel(val id: String?)

View File

@@ -0,0 +1,7 @@
package dev.adriankuta.kahootquiz.domain.models
data class Choice(
val answer: String?,
val correct: Boolean?,
val languageInfo: LanguageInfo?
)

View File

@@ -0,0 +1,11 @@
package dev.adriankuta.kahootquiz.domain.models
// Slider range for "slider" question type
data class ChoiceRange(
val start: Int?,
val end: Int?,
val step: Int?,
val correct: Int?,
val tolerance: Int?
)

View File

@@ -0,0 +1,8 @@
package dev.adriankuta.kahootquiz.domain.models
// Content tags domain model
data class ContentTags(
val curriculumCodes: List<String>?,
val generatedCurriculumCodes: List<String>?
)

View File

@@ -0,0 +1,17 @@
package dev.adriankuta.kahootquiz.domain.models
// Cover metadata and related domain models
data class CoverMetadata(
val id: String?,
val altText: String?,
val contentType: String?,
val origin: String?,
val externalRef: String?,
val resources: String?,
val width: Int?,
val height: Int?,
val extractedColors: List<ExtractedColor>?,
val blurhash: String?,
val crop: Crop?
)

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
// Crop descriptor
data class Crop(
val origin: Point?,
val target: Point?,
val circular: Boolean?
)

View File

@@ -0,0 +1,8 @@
package dev.adriankuta.kahootquiz.domain.models
// Color extracted from cover image
data class ExtractedColor(
val swatch: String?,
val rgbHex: String?
)

View File

@@ -0,0 +1,8 @@
package dev.adriankuta.kahootquiz.domain.models
// Featured list membership
data class FeaturedListMembership(
val list: String?,
val addedAt: Long?
)

View File

@@ -0,0 +1,16 @@
package dev.adriankuta.kahootquiz.domain.models
// Image metadata appearing in multiple places
data class ImageMetadata(
val id: String?,
val altText: String? = null,
val contentType: String?,
val origin: String? = null,
val externalRef: String? = null,
val resources: String? = null,
val width: Int? = null,
val height: Int? = null,
val effects: List<String>? = null,
val crop: Crop? = null
)

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
// Common simple models reused across the domain layer
data class LanguageInfo(
val language: String?,
val lastUpdatedOn: Long?,
val readAloudSupported: Boolean?
)

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
// Last edit information
data class LastEdit(
val editorUserId: String?,
val editorUsername: String?,
val editTimestamp: Long?
)

View File

@@ -0,0 +1,18 @@
package dev.adriankuta.kahootquiz.domain.models
// Generic media item on question
data class MediaItem(
val type: String?,
val zIndex: Int?,
val isColorOnly: Boolean?,
val id: String?,
val altText: String? = null,
val contentType: String?,
val origin: String? = null,
val externalRef: String? = null,
val resources: String? = null,
val width: Int? = null,
val height: Int? = null,
val crop: Crop? = null
)

View File

@@ -0,0 +1,11 @@
package dev.adriankuta.kahootquiz.domain.models
// Metadata section domain models
data class Metadata(
val access: Access?,
val duplicationProtection: Boolean?,
val featuredListMemberships: List<FeaturedListMembership>?,
val lastEdit: LastEdit?,
val versionMetadata: VersionMetadata?
)

View File

@@ -0,0 +1,8 @@
package dev.adriankuta.kahootquiz.domain.models
// Geometry helpers
data class Point(
val x: Int?,
val y: Int?
)

View File

@@ -0,0 +1,23 @@
package dev.adriankuta.kahootquiz.domain.models
import kotlin.time.Duration
// Question and choice related domain models
data class Question(
val type: String?,
val question: String?,
val time: Duration?,
val points: Boolean?,
val pointsMultiplier: Int?,
val choices: List<Choice>?,
val layout: String?,
val image: String?,
val imageMetadata: ImageMetadata?,
val resources: String?,
val video: Video?,
val questionFormat: Int?,
val languageInfo: LanguageInfo?,
val media: List<MediaItem>?,
val choiceRange: ChoiceRange?
)

View File

@@ -0,0 +1,3 @@
package dev.adriankuta.kahootquiz.domain.models
// Moved: data classes have been split into separate files.

View File

@@ -1,5 +1,35 @@
package dev.adriankuta.kahootquiz.domain.models
// Domain model representing a Quiz and its nested data
data class Quiz(
val id: String
val id: QuizId,
val language: String?,
val creator: String?,
val creatorUsername: String?,
val compatibilityLevel: Int?,
val creatorPrimaryUsage: String?,
val folderId: String?,
val themeId: String?,
val visibility: Int?,
val audience: String?,
val title: String?,
val description: String?,
val quizType: String?,
val cover: String?,
val coverMetadata: CoverMetadata?,
val questions: List<Question>,
val contentTags: ContentTags?,
val metadata: Metadata?,
val resources: String?,
val slug: String?,
val languageInfo: LanguageInfo?,
val inventoryItemIds: List<String>,
val channels: List<Channel>,
val isValid: Boolean?,
val playAsGuest: Boolean?,
val hasRestrictedContent: Boolean?,
val type: String?,
val created: Long?,
val modified: Long?
)

View File

@@ -0,0 +1,5 @@
package dev.adriankuta.kahootquiz.domain.models
data class QuizId(
val value: String,
)

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
// Version metadata
data class VersionMetadata(
val version: Int?,
val created: Long?,
val creator: String?
)

View File

@@ -0,0 +1,9 @@
package dev.adriankuta.kahootquiz.domain.models
data class Video(
val id: String? = null,
val startTime: Int?,
val endTime: Int?,
val service: String?,
val fullUrl: String?
)