FIRST SUCCESS RUN

This commit is contained in:
2025-08-07 17:37:06 +03:00
parent b63eca8440
commit 5b613f7cc8
43 changed files with 366 additions and 314 deletions

View File

@@ -45,11 +45,13 @@ dependencies {
// [DEPENDENCY] Coroutines
implementation(Libs.coroutinesCore)
// [DEPENDENCY] Networking (Retrofit, Gson)
// [DEPENDENCY] Networking (Retrofit, Moshi)
implementation(Libs.retrofit)
implementation(Libs.converterGson)
implementation(Libs.converterMoshi)
implementation(Libs.okhttp)
implementation(Libs.okhttpLoggingInterceptor)
implementation(Libs.moshiKotlin)
kapt(Libs.moshiCodegen)
// [DEPENDENCY] Database (Room)
implementation(Libs.roomRuntime)
@@ -64,6 +66,8 @@ dependencies {
testImplementation(Libs.junit)
androidTestImplementation(Libs.extJunit)
androidTestImplementation(Libs.espressoCore)
}
kapt {

View File

@@ -2,8 +2,11 @@
// [FILE] CustomFieldDto.kt
// [SEMANTICS] data_transfer_object, custom_field
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.CustomField
// [CORE-LOGIC]
@@ -11,10 +14,11 @@ import com.homebox.lens.domain.model.CustomField
* [CONTRACT]
* DTO для кастомного поля.
*/
@JsonClass(generateAdapter = true)
data class CustomFieldDto(
@SerializedName("name") val name: String,
@SerializedName("value") val value: String,
@SerializedName("type") val type: String
@Json(name = "name") val name: String,
@Json(name = "value") val value: String,
@Json(name = "type") val type: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] GroupStatisticsDto.kt
// [SEMANTICS] data_transfer_object, statistics
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.GroupStatistics
// [CORE-LOGIC]
@@ -11,11 +14,12 @@ import com.homebox.lens.domain.model.GroupStatistics
* [CONTRACT]
* DTO для статистики.
*/
@JsonClass(generateAdapter = true)
data class GroupStatisticsDto(
@SerializedName("items") val items: Int,
@SerializedName("labels") val labels: Int,
@SerializedName("locations") val locations: Int,
@SerializedName("totalValue") val totalValue: Double
@Json(name = "items") val items: Int,
@Json(name = "labels") val labels: Int,
@Json(name = "locations") val locations: Int,
@Json(name = "totalValue") val totalValue: Double
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ImageDto.kt
// [SEMANTICS] data_transfer_object, image
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.Image
// [CORE-LOGIC]
@@ -14,10 +17,11 @@ import com.homebox.lens.domain.model.Image
* @property path Путь к файлу.
* @property isPrimary Является ли основным.
*/
@JsonClass(generateAdapter = true)
data class ImageDto(
@SerializedName("id") val id: String,
@SerializedName("path") val path: String,
@SerializedName("isPrimary") val isPrimary: Boolean
@Json(name = "id") val id: String,
@Json(name = "path") val path: String,
@Json(name = "isPrimary") val isPrimary: Boolean
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ItemAttachmentDto.kt
// [SEMANTICS] data_transfer_object, attachment
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.ItemAttachment
// [CORE-LOGIC]
@@ -11,13 +14,14 @@ import com.homebox.lens.domain.model.ItemAttachment
* [CONTRACT]
* DTO для вложения.
*/
@JsonClass(generateAdapter = true)
data class ItemAttachmentDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("path") val path: String,
@SerializedName("type") val type: String,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "path") val path: String,
@Json(name = "type") val type: String,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ItemCreateDto.kt
// [SEMANTICS] data_transfer_object, item_creation
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.ItemCreate
// [CORE-LOGIC]
@@ -11,20 +14,21 @@ import com.homebox.lens.domain.model.ItemCreate
* [CONTRACT]
* DTO для создания вещи.
*/
@JsonClass(generateAdapter = true)
data class ItemCreateDto(
@SerializedName("name") val name: String,
@SerializedName("assetId") val assetId: String?,
@SerializedName("description") val description: String?,
@SerializedName("notes") val notes: String?,
@SerializedName("serialNumber") val serialNumber: String?,
@SerializedName("quantity") val quantity: Int?,
@SerializedName("value") val value: Double?,
@SerializedName("purchasePrice") val purchasePrice: Double?,
@SerializedName("purchaseDate") val purchaseDate: String?,
@SerializedName("warrantyUntil") val warrantyUntil: String?,
@SerializedName("locationId") val locationId: String?,
@SerializedName("parentId") val parentId: String?,
@SerializedName("labelIds") val labelIds: List<String>?
@Json(name = "name") val name: String,
@Json(name = "assetId") val assetId: String?,
@Json(name = "description") val description: String?,
@Json(name = "notes") val notes: String?,
@Json(name = "serialNumber") val serialNumber: String?,
@Json(name = "quantity") val quantity: Int?,
@Json(name = "value") val value: Double?,
@Json(name = "purchasePrice") val purchasePrice: Double?,
@Json(name = "purchaseDate") val purchaseDate: String?,
@Json(name = "warrantyUntil") val warrantyUntil: String?,
@Json(name = "locationId") val locationId: String?,
@Json(name = "parentId") val parentId: String?,
@Json(name = "labelIds") val labelIds: List<String>?
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ItemOutDto.kt
// [SEMANTICS] data_transfer_object, item_detailed
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.ItemOut
// [CORE-LOGIC]
@@ -11,29 +14,30 @@ import com.homebox.lens.domain.model.ItemOut
* [CONTRACT]
* DTO для полной модели вещи.
*/
@JsonClass(generateAdapter = true)
data class ItemOutDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("assetId") val assetId: String?,
@SerializedName("description") val description: String?,
@SerializedName("notes") val notes: String?,
@SerializedName("serialNumber") val serialNumber: String?,
@SerializedName("quantity") val quantity: Int,
@SerializedName("isArchived") val isArchived: Boolean,
@SerializedName("value") val value: Double,
@SerializedName("purchasePrice") val purchasePrice: Double?,
@SerializedName("purchaseDate") val purchaseDate: String?,
@SerializedName("warrantyUntil") val warrantyUntil: String?,
@SerializedName("location") val location: LocationOutDto?,
@SerializedName("parent") val parent: ItemSummaryDto?,
@SerializedName("children") val children: List<ItemSummaryDto>,
@SerializedName("labels") val labels: List<LabelOutDto>,
@SerializedName("attachments") val attachments: List<ItemAttachmentDto>,
@SerializedName("images") val images: List<ImageDto>,
@SerializedName("fields") val fields: List<CustomFieldDto>,
@SerializedName("maintenance") val maintenance: List<MaintenanceEntryDto>,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "assetId") val assetId: String?,
@Json(name = "description") val description: String?,
@Json(name = "notes") val notes: String?,
@Json(name = "serialNumber") val serialNumber: String?,
@Json(name = "quantity") val quantity: Int,
@Json(name = "isArchived") val isArchived: Boolean,
@Json(name = "value") val value: Double,
@Json(name = "purchasePrice") val purchasePrice: Double?,
@Json(name = "purchaseDate") val purchaseDate: String?,
@Json(name = "warrantyUntil") val warrantyUntil: String?,
@Json(name = "location") val location: LocationOutDto?,
@Json(name = "parent") val parent: ItemSummaryDto?,
@Json(name = "children") val children: List<ItemSummaryDto>,
@Json(name = "labels") val labels: List<LabelOutDto>,
@Json(name = "attachments") val attachments: List<ItemAttachmentDto>,
@Json(name = "images") val images: List<ImageDto>,
@Json(name = "fields") val fields: List<CustomFieldDto>,
@Json(name = "maintenance") val maintenance: List<MaintenanceEntryDto>,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ItemSummaryDto.kt
// [SEMANTICS] data_transfer_object, item_summary
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.ItemSummary
// [CORE-LOGIC]
@@ -11,17 +14,18 @@ import com.homebox.lens.domain.model.ItemSummary
* [CONTRACT]
* DTO для сокращенной модели вещи.
*/
@JsonClass(generateAdapter = true)
data class ItemSummaryDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("assetId") val assetId: String?,
@SerializedName("image") val image: ImageDto?,
@SerializedName("isArchived") val isArchived: Boolean,
@SerializedName("labels") val labels: List<LabelOutDto>,
@SerializedName("location") val location: LocationOutDto?,
@SerializedName("value") val value: Double,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "assetId") val assetId: String?,
@Json(name = "image") val image: ImageDto?,
@Json(name = "isArchived") val isArchived: Boolean,
@Json(name = "labels") val labels: List<LabelOutDto>,
@Json(name = "location") val location: LocationOutDto?,
@Json(name = "value") val value: Double,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] ItemUpdateDto.kt
// [SEMANTICS] data_transfer_object, item_update
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.ItemUpdate
// [CORE-LOGIC]
@@ -11,21 +14,22 @@ import com.homebox.lens.domain.model.ItemUpdate
* [CONTRACT]
* DTO для обновления вещи.
*/
@JsonClass(generateAdapter = true)
data class ItemUpdateDto(
@SerializedName("name") val name: String?,
@SerializedName("assetId") val assetId: String?,
@SerializedName("description") val description: String?,
@SerializedName("notes") val notes: String?,
@SerializedName("serialNumber") val serialNumber: String?,
@SerializedName("quantity") val quantity: Int?,
@SerializedName("isArchived") val isArchived: Boolean?,
@SerializedName("value") val value: Double?,
@SerializedName("purchasePrice") val purchasePrice: Double?,
@SerializedName("purchaseDate") val purchaseDate: String?,
@SerializedName("warrantyUntil") val warrantyUntil: String?,
@SerializedName("locationId") val locationId: String?,
@SerializedName("parentId") val parentId: String?,
@SerializedName("labelIds") val labelIds: List<String>?
@Json(name = "name") val name: String?,
@Json(name = "assetId") val assetId: String?,
@Json(name = "description") val description: String?,
@Json(name = "notes") val notes: String?,
@Json(name = "serialNumber") val serialNumber: String?,
@Json(name = "quantity") val quantity: Int?,
@Json(name = "isArchived") val isArchived: Boolean?,
@Json(name = "value") val value: Double?,
@Json(name = "purchasePrice") val purchasePrice: Double?,
@Json(name = "purchaseDate") val purchaseDate: String?,
@Json(name = "warrantyUntil") val warrantyUntil: String?,
@Json(name = "locationId") val locationId: String?,
@Json(name = "parentId") val parentId: String?,
@Json(name = "labelIds") val labelIds: List<String>?
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] LabelOutDto.kt
// [SEMANTICS] data_transfer_object, label
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.LabelOut
// [CORE-LOGIC]
@@ -11,13 +14,14 @@ import com.homebox.lens.domain.model.LabelOut
* [CONTRACT]
* DTO для метки.
*/
@JsonClass(generateAdapter = true)
data class LabelOutDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("color") val color: String,
@SerializedName("isArchived") val isArchived: Boolean,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "color") val color: String,
@Json(name = "isArchived") val isArchived: Boolean,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] LocationOutCountDto.kt
// [SEMANTICS] data_transfer_object, location, count
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.LocationOutCount
// [CORE-LOGIC]
@@ -11,14 +14,15 @@ import com.homebox.lens.domain.model.LocationOutCount
* [CONTRACT]
* DTO для местоположения со счетчиком.
*/
@JsonClass(generateAdapter = true)
data class LocationOutCountDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("color") val color: String,
@SerializedName("isArchived") val isArchived: Boolean,
@SerializedName("itemCount") val itemCount: Int,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "color") val color: String,
@Json(name = "isArchived") val isArchived: Boolean,
@Json(name = "itemCount") val itemCount: Int,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] LocationOutDto.kt
// [SEMANTICS] data_transfer_object, location
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.LocationOut
// [CORE-LOGIC]
@@ -11,13 +14,14 @@ import com.homebox.lens.domain.model.LocationOut
* [CONTRACT]
* DTO для местоположения.
*/
@JsonClass(generateAdapter = true)
data class LocationOutDto(
@SerializedName("id") val id: String,
@SerializedName("name") val name: String,
@SerializedName("color") val color: String,
@SerializedName("isArchived") val isArchived: Boolean,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "name") val name: String,
@Json(name = "color") val color: String,
@Json(name = "isArchived") val isArchived: Boolean,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] MaintenanceEntryDto.kt
// [SEMANTICS] data_transfer_object, maintenance
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.MaintenanceEntry
// [CORE-LOGIC]
@@ -11,15 +14,16 @@ import com.homebox.lens.domain.model.MaintenanceEntry
* [CONTRACT]
* DTO для записи об обслуживании.
*/
@JsonClass(generateAdapter = true)
data class MaintenanceEntryDto(
@SerializedName("id") val id: String,
@SerializedName("itemId") val itemId: String,
@SerializedName("title") val title: String,
@SerializedName("details") val details: String?,
@SerializedName("dueAt") val dueAt: String?,
@SerializedName("completedAt") val completedAt: String?,
@SerializedName("createdAt") val createdAt: String,
@SerializedName("updatedAt") val updatedAt: String
@Json(name = "id") val id: String,
@Json(name = "itemId") val itemId: String,
@Json(name = "title") val title: String,
@Json(name = "details") val details: String?,
@Json(name = "dueAt") val dueAt: String?,
@Json(name = "completedAt") val completedAt: String?,
@Json(name = "createdAt") val createdAt: String,
@Json(name = "updatedAt") val updatedAt: String
)
/**

View File

@@ -2,8 +2,11 @@
// [FILE] PaginationResultDto.kt
// [SEMANTICS] data_transfer_object, pagination
package com.homebox.lens.data.api.dto
// [IMPORTS]
import com.google.gson.annotations.SerializedName
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.homebox.lens.domain.model.PaginationResult
// [CORE-LOGIC]
@@ -11,11 +14,12 @@ import com.homebox.lens.domain.model.PaginationResult
* [CONTRACT]
* DTO для постраничных результатов.
*/
@JsonClass(generateAdapter = true)
data class PaginationResultDto<T>(
@SerializedName("items") val items: List<T>,
@SerializedName("page") val page: Int,
@SerializedName("pageSize") val pageSize: Int,
@SerializedName("total") val total: Int
@Json(name = "items") val items: List<T>,
@Json(name = "page") val page: Int,
@Json(name = "pageSize") val pageSize: Int,
@Json(name = "total") val total: Int
)
/**

View File

@@ -4,13 +4,17 @@
package com.homebox.lens.data.db.entity
import androidx.room.Entity
import androidx.room.Index
// [CONTRACT]
/**
* [ENTITY: RoomEntity('ItemLabelCrossRef')]
* [PURPOSE] Таблица для связи "многие-ко-многим" между ItemEntity и LabelEntity.
*/
@Entity(primaryKeys = ["itemId", "labelId"])
@Entity(
primaryKeys = ["itemId", "labelId"],
indices = [Index(value = ["labelId"])]
)
data class ItemLabelCrossRef(
val itemId: String,
val labelId: String

View File

@@ -3,10 +3,11 @@
package com.homebox.lens.data.di
import com.homebox.lens.data.api.HomeboxApiService
import com.homebox.lens.data.repository.ItemRepositoryImpl
import com.homebox.lens.domain.repository.ItemRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@@ -18,14 +19,14 @@ import javax.inject.Singleton
*/
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
object RepositoryModule {
// [PROVIDER]
@Binds
@Provides
@Singleton
abstract fun bindItemRepository(
itemRepositoryImpl: ItemRepositoryImpl
): ItemRepository
fun provideItemRepository(apiService: HomeboxApiService): ItemRepository {
return ItemRepositoryImpl(apiService)
}
}
// [END_FILE_RepositoryModule.kt]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.data.repository
// [FILE] ItemRepositoryImpl.kt
// [SEMANTICS] data_repository, implementation, network
package com.homebox.lens.data.repository
// [IMPORTS]
import com.homebox.lens.data.api.HomeboxApiService
import com.homebox.lens.data.api.dto.toDomain
@@ -9,6 +9,7 @@ import com.homebox.lens.data.api.dto.toDto
import com.homebox.lens.domain.model.*
import com.homebox.lens.domain.repository.ItemRepository
import javax.inject.Inject
import javax.inject.Singleton
// [CORE-LOGIC]
/**
@@ -16,6 +17,7 @@ import javax.inject.Inject
* Реализация репозитория для работы с данными о вещах.
* @param apiService Сервис для взаимодействия с Homebox API.
*/
@Singleton
class ItemRepositoryImpl @Inject constructor(
private val apiService: HomeboxApiService
) : ItemRepository {