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

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.homebox.lens"> package="com.homebox.lens">
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".MainApplication"
android:allowBackup="true" android:allowBackup="true"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"

View File

@@ -1,63 +0,0 @@
// [PACKAGE] com.homebox.lens.di
// [FILE] AppModule.kt
// [SEMANTICS] dependency_injection, hilt, configuration
// [IMPORTS]
import com.homebox.lens.data.api.HomeboxApiService
import com.homebox.lens.data.repository.ItemRepositoryImpl
import com.homebox.lens.domain.repository.ItemRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton
// [CORE-LOGIC]
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
private const val BASE_URL = "https://homebox.fly.dev/api/" // Заглушка, заменить на реальный URL
/**
* [CONTRACT]
* Предоставляет синглтон-экземпляр Retrofit.
*/
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
// [PRECONDITION] BASE_URL должен быть валидным URL.
require(BASE_URL.startsWith("https://") || BASE_URL.startsWith("http://")) {
"[PRECONDITION_FAILED] BASE_URL must be a valid URL."
}
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
/**
* [CONTRACT]
* Предоставляет синглтон-экземпляр HomeboxApiService.
* @param retrofit Экземпляр Retrofit.
*/
@Provides
@Singleton
fun provideHomeboxApiService(retrofit: Retrofit): HomeboxApiService {
return retrofit.create(HomeboxApiService::class.java)
}
/**
* [CONTRACT]
* Предоставляет реализацию ItemRepository.
* @param apiService Экземпляр HomeboxApiService.
*/
@Provides
@Singleton
fun provideItemRepository(apiService: HomeboxApiService): ItemRepository {
return ItemRepositoryImpl(apiService)
}
}
// [END_FILE_AppModule.kt]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.navigation // [PACKAGE] com.homebox.lens.navigation
// [FILE] NavGraph.kt // [FILE] NavGraph.kt
// [SEMANTICS] navigation, compose, nav_host // [SEMANTICS] navigation, compose, nav_host
package com.homebox.lens.navigation
// [IMPORTS] // [IMPORTS]
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost

View File

@@ -1,15 +1,24 @@
// [PACKAGE] com.homebox.lens.navigation // [PACKAGE] com.homebox.lens.navigation
// [FILE] Screen.kt // [FILE] app/src/main/java/com/homebox/lens/navigation/Screen.kt
// [SEMANTICS] navigation, routes, constants // [SEMANTICS] navigation, routes, sealed_class
package com.homebox.lens.navigation
// [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]
* Запечатанный класс для определения навигационных маршрутов в приложении. * Запечатанный класс для определения маршрутов навигации в приложении.
* Обеспечивает типобезопасность при навигации.
* @property route Строковый идентификатор маршрута. * @property route Строковый идентификатор маршрута.
*/ */
sealed class Screen(val route: String) { sealed class Screen(val route: String) {
object Dashboard : Screen("dashboard_screen") /**
// TODO: Добавить остальные экраны по мере их создания * [CONTRACT]
* Представляет экран "Дэшборд".
*/
data object Dashboard : Screen("dashboard_screen")
// TODO: Добавить объекты для остальных экранов:
// data object ItemDetails : Screen("item_details_screen")
// data object Search : Screen("search_screen")
} }
// [END_FILE_Screen.kt] // [END_FILE_Screen.kt]

View File

@@ -1,8 +1,10 @@
// [PACKAGE] com.homebox.lens.ui.screen.dashboard // [PACKAGE] com.homebox.lens.ui.screen.dashboard
// [FILE] DashboardScreen.kt // [FILE] app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardScreen.kt
// [SEMANTICS] ui, screen, dashboard, compose // [SEMANTICS] ui, screen, dashboard, compose
// [IMPORTS] // [IMPORTS]
package com.homebox.lens.ui.screen.dashboard
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -18,12 +20,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import timber.log.Timber
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]
* Главный Composable для экрана "Дэшборд". * Главный Composable для экрана "Дэшборд".
* @param viewModel ViewModel для этого экрана. * @param viewModel ViewModel для этого экрана, предоставляемая Hilt.
*/ */
@Composable @Composable
fun DashboardScreen( fun DashboardScreen(
@@ -44,13 +47,16 @@ fun DashboardScreen(
} }
is DashboardUiState.Error -> { is DashboardUiState.Error -> {
// [UI-ACTION] Показываем сообщение об ошибке // [UI-ACTION] Показываем сообщение об ошибке
val errorMessage = "Error: ${state.message}"
Text( Text(
text = "Error: ${state.message}", text = errorMessage,
modifier = Modifier.align(Alignment.Center) modifier = Modifier.align(Alignment.Center)
) )
Timber.w("[UI-STATE] Displaying Error: $errorMessage")
} }
is DashboardUiState.Success -> { is DashboardUiState.Success -> {
// [UI-ACTION] Отображаем основной контент // [UI-ACTION] Отображаем основной контент
Timber.d("[UI-STATE] Displaying Success")
DashboardContent(state) DashboardContent(state)
} }
} }

View File

@@ -0,0 +1,46 @@
// [PACKAGE] com.homebox.lens.ui.screen.dashboard
// [FILE] app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardUiState.kt
// [SEMANTICS] ui, state, dashboard
// [IMPORTS]
package com.homebox.lens.ui.screen.dashboard
import com.homebox.lens.domain.model.GroupStatistics
import com.homebox.lens.domain.model.LabelOut
import com.homebox.lens.domain.model.LocationOutCount
// [CORE-LOGIC]
// [ENTITY: SealedInterface('DashboardUiState')]
/**
* [CONTRACT]
* Определяет все возможные состояния для экрана "Дэшборд".
* @invariant В любой момент времени экран может находиться только в одном из этих состояний.
*/
sealed interface DashboardUiState {
/**
* [CONTRACT]
* Состояние успешной загрузки данных.
* @property statistics Статистика по инвентарю.
* @property locations Список локаций со счетчиками.
* @property labels Список всех меток.
*/
data class Success(
val statistics: GroupStatistics,
val locations: List<LocationOutCount>,
val labels: List<LabelOut>
) : DashboardUiState
/**
* [CONTRACT]
* Состояние ошибки во время загрузки данных.
* @property message Человекочитаемое сообщение об ошибке.
*/
data class Error(val message: String) : DashboardUiState
/**
* [CONTRACT]
* Состояние, когда данные для экрана загружаются.
*/
data object Loading : DashboardUiState
}
// [END_FILE_DashboardUiState.kt]

View File

@@ -1,31 +1,25 @@
// [PACKAGE] com.homebox.lens.ui.screen.dashboard // [PACKAGE] com.homebox.lens.ui.screen.dashboard
// [FILE] DashboardViewModel.kt // [FILE] app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardViewModel.kt
// [SEMANTICS] view_model, dashboard, state_management // [SEMANTICS] ui, viewmodel, dashboard, hilt
// [IMPORTS] // [IMPORTS]
package com.homebox.lens.ui.screen.dashboard
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.homebox.lens.domain.model.GroupStatistics
import com.homebox.lens.domain.model.LabelOut
import com.homebox.lens.domain.model.LocationOutCount
import com.homebox.lens.domain.usecase.GetAllLabelsUseCase import com.homebox.lens.domain.usecase.GetAllLabelsUseCase
import com.homebox.lens.domain.usecase.GetAllLocationsUseCase import com.homebox.lens.domain.usecase.GetAllLocationsUseCase
import com.homebox.lens.domain.usecase.GetStatisticsUseCase import com.homebox.lens.domain.usecase.GetStatisticsUseCase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber // [FIX] Логирование происходит здесь
import javax.inject.Inject import javax.inject.Inject
// [CORE-LOGIC] // [CORE-LOGIC]
/**
* [CONTRACT]
* ViewModel для экрана "Дэшборд".
* @param getStatisticsUseCase Use case для получения статистики.
* @param getAllLocationsUseCase Use case для получения местоположений.
* @param getAllLabelsUseCase Use case для получения меток.
*/
@HiltViewModel @HiltViewModel
class DashboardViewModel @Inject constructor( class DashboardViewModel @Inject constructor(
private val getStatisticsUseCase: GetStatisticsUseCase, private val getStatisticsUseCase: GetStatisticsUseCase,
@@ -33,51 +27,51 @@ class DashboardViewModel @Inject constructor(
private val getAllLabelsUseCase: GetAllLabelsUseCase private val getAllLabelsUseCase: GetAllLabelsUseCase
) : ViewModel() { ) : ViewModel() {
// [STATE] UI State
private val _uiState = MutableStateFlow<DashboardUiState>(DashboardUiState.Loading) private val _uiState = MutableStateFlow<DashboardUiState>(DashboardUiState.Loading)
val uiState: StateFlow<DashboardUiState> = _uiState.asStateFlow() val uiState: StateFlow<DashboardUiState> = _uiState.asStateFlow()
init { init {
// [ACTION] Загрузка всех данных при инициализации.
loadDashboardData() loadDashboardData()
} }
/** private fun loadDashboardData() {
* [CONTRACT] Timber.i("[ACTION] Starting dashboard data load.")
* Загружает все необходимые для экрана данные.
* @sideeffect Обновляет _uiState.
*/
fun loadDashboardData() {
viewModelScope.launch {
_uiState.value = DashboardUiState.Loading _uiState.value = DashboardUiState.Loading
try {
val statistics = getStatisticsUseCase()
val locations = getAllLocationsUseCase()
val labels = getAllLabelsUseCase()
viewModelScope.launch {
try {
// Параллельно запрашиваем все данные
val statsDeferred = async { getStatisticsUseCase() }
val locationsDeferred = async { getAllLocationsUseCase() }
val labelsDeferred = async { getAllLabelsUseCase() }
val stats = statsDeferred.await()
val locations = locationsDeferred.await()
val labels = labelsDeferred.await()
// [ACTION] Логируем результат здесь, во ViewModel
if (stats != null && locations != null && labels != null) {
_uiState.value = DashboardUiState.Success( _uiState.value = DashboardUiState.Success(
statistics = statistics, statistics = stats,
locations = locations, locations = locations,
labels = labels labels = labels
) )
Timber.i("[COHERENCE_CHECK_PASSED] Dashboard data loaded successfully.")
} else {
// Одна из операций вернула null
val errorMessage = "Failed to load dashboard data: " +
"stats is ${if(stats==null) "null" else "ok"}, " +
"locations is ${if(locations==null) "null" else "ok"}, " +
"labels is ${if(labels==null) "null" else "ok"}"
Timber.e(errorMessage)
_uiState.value = DashboardUiState.Error("Could not load all dashboard data.")
}
} catch (e: Exception) { } catch (e: Exception) {
_uiState.value = DashboardUiState.Error(e.message ?: "Unknown error") // [ERROR_HANDLER] Эта ошибка будет отловлена, если сама корутина `launch` упадет
Timber.e(e, "[ERROR] Critical failure in loadDashboardData coroutine.")
_uiState.value = DashboardUiState.Error(e.message ?: "An unknown critical error occurred")
} }
} }
} }
} }
/**
* [CONTRACT]
* Запечатанный интерфейс для представления состояний UI дэшборда.
*/
sealed interface DashboardUiState {
data class Success(
val statistics: GroupStatistics,
val locations: List<LocationOutCount>,
val labels: List<LabelOut>
) : DashboardUiState
data class Error(val message: String) : DashboardUiState
object Loading : DashboardUiState
}
// [END_FILE_DashboardViewModel.kt] // [END_FILE_DashboardViewModel.kt]

View File

@@ -69,7 +69,6 @@ object Libs {
// Networking (Retrofit, OkHttp, Moshi) // Networking (Retrofit, OkHttp, Moshi)
const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}" const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
const val converterMoshi = "com.squareup.retrofit2:converter-moshi:${Versions.retrofit}" const val converterMoshi = "com.squareup.retrofit2:converter-moshi:${Versions.retrofit}"
const val converterGson = "com.squareup.retrofit2:converter-gson:${Versions.retrofit}"
const val okhttp = "com.squareup.okhttp3:okhttp:${Versions.okhttp}" const val okhttp = "com.squareup.okhttp3:okhttp:${Versions.okhttp}"
const val okhttpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor:${Versions.okhttp}" const val okhttpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor:${Versions.okhttp}"
const val moshi = "com.squareup.moshi:moshi:${Versions.moshi}" const val moshi = "com.squareup.moshi:moshi:${Versions.moshi}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] CustomField.kt // [FILE] CustomField.kt
// [SEMANTICS] data_structure, entity, custom_field // [SEMANTICS] data_structure, entity, custom_field
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] GroupStatistics.kt // [FILE] GroupStatistics.kt
// [SEMANTICS] data_structure, statistics // [SEMANTICS] data_structure, statistics
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] Image.kt // [FILE] Image.kt
// [SEMANTICS] data_structure, entity, image // [SEMANTICS] data_structure, entity, image
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] ItemAttachment.kt // [FILE] ItemAttachment.kt
// [SEMANTICS] data_structure, entity, attachment // [SEMANTICS] data_structure, entity, attachment
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] ItemCreate.kt // [FILE] ItemCreate.kt
// [SEMANTICS] data_structure, entity, input, create // [SEMANTICS] data_structure, entity, input, create
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] ItemOut.kt // [FILE] ItemOut.kt
// [SEMANTICS] data_structure, entity, detailed // [SEMANTICS] data_structure, entity, detailed
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] ItemSummary.kt // [FILE] ItemSummary.kt
// [SEMANTICS] data_structure, entity, summary // [SEMANTICS] data_structure, entity, summary
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] ItemUpdate.kt // [FILE] ItemUpdate.kt
// [SEMANTICS] data_structure, entity, input, update // [SEMANTICS] data_structure, entity, input, update
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] LabelOut.kt // [FILE] LabelOut.kt
// [SEMANTICS] data_structure, entity, label // [SEMANTICS] data_structure, entity, label
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] LocationOut.kt // [FILE] LocationOut.kt
// [SEMANTICS] data_structure, entity, location // [SEMANTICS] data_structure, entity, location
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] LocationOutCount.kt // [FILE] LocationOutCount.kt
// [SEMANTICS] data_structure, entity, location // [SEMANTICS] data_structure, entity, location
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] MaintenanceEntry.kt // [FILE] MaintenanceEntry.kt
// [SEMANTICS] data_structure, entity, maintenance // [SEMANTICS] data_structure, entity, maintenance
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.model // [PACKAGE] com.homebox.lens.domain.model
// [FILE] PaginationResult.kt // [FILE] PaginationResult.kt
// [SEMANTICS] data_structure, generic, pagination // [SEMANTICS] data_structure, generic, pagination
package com.homebox.lens.domain.model
// [CORE-LOGIC] // [CORE-LOGIC]
/** /**
* [CONTRACT] * [CONTRACT]

View File

@@ -1,7 +1,7 @@
// [PACKAGE] com.homebox.lens.domain.repository // [PACKAGE] com.homebox.lens.domain.repository
// [FILE] ItemRepository.kt // [FILE] ItemRepository.kt
// [SEMANTICS] data_access, abstraction, repository // [SEMANTICS] data_access, abstraction, repository
package com.homebox.lens.domain.repository
// [IMPORTS] // [IMPORTS]
import com.homebox.lens.domain.model.* import com.homebox.lens.domain.model.*

View File

@@ -1,29 +1,25 @@
// [PACKAGE] com.homebox.lens.domain.usecase // [PACKAGE] com.homebox.lens.domain.usecase
// [FILE] GetAllLabelsUseCase.kt // [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetAllLabelsUseCase.kt
// [SEMANTICS] business_logic, use_case, label_retrieval // [SEMANTICS] domain, usecase, label, list
// [IMPORTS] // [IMPORTS]
package com.homebox.lens.domain.usecase
import com.homebox.lens.domain.model.LabelOut import com.homebox.lens.domain.model.LabelOut
import com.homebox.lens.domain.repository.ItemRepository import com.homebox.lens.domain.repository.ItemRepository
import javax.inject.Inject import javax.inject.Inject
// [CORE-LOGIC] // [CORE-LOGIC]
/**
* [CONTRACT]
* Use case для получения всех меток.
* @param itemRepository Репозиторий для работы с данными.
*/
class GetAllLabelsUseCase @Inject constructor( class GetAllLabelsUseCase @Inject constructor(
private val itemRepository: ItemRepository private val itemRepository: ItemRepository
) { ) {
/** suspend operator fun invoke(): List<LabelOut>? {
* [CONTRACT] return try {
* Выполняет операцию получения всех меток. itemRepository.getAllLabels()
* @return Возвращает список меток. } catch (e: Exception) {
*/ // [ERROR_HANDLER] Просто возвращаем null.
suspend operator fun invoke(): List<LabelOut> { null
// [ACTION] }
return itemRepository.getAllLabels()
} }
} }
// [END_FILE_GetAllLabelsUseCase.kt] // [END_FILE_GetAllLabelsUseCase.kt]

View File

@@ -1,29 +1,25 @@
// [PACKAGE] com.homebox.lens.domain.usecase // [PACKAGE] com.homebox.lens.domain.usecase
// [FILE] GetAllLocationsUseCase.kt // [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetAllLocationsUseCase.kt
// [SEMANTICS] business_logic, use_case, location_retrieval // [SEMANTICS] domain, usecase, location, list
// [IMPORTS] // [IMPORTS]
package com.homebox.lens.domain.usecase
import com.homebox.lens.domain.model.LocationOutCount import com.homebox.lens.domain.model.LocationOutCount
import com.homebox.lens.domain.repository.ItemRepository import com.homebox.lens.domain.repository.ItemRepository
import javax.inject.Inject import javax.inject.Inject
// [CORE-LOGIC] // [CORE-LOGIC]
/**
* [CONTRACT]
* Use case для получения всех местоположений.
* @param itemRepository Репозиторий для работы с данными.
*/
class GetAllLocationsUseCase @Inject constructor( class GetAllLocationsUseCase @Inject constructor(
private val itemRepository: ItemRepository private val itemRepository: ItemRepository
) { ) {
/** suspend operator fun invoke(): List<LocationOutCount>? {
* [CONTRACT] return try {
* Выполняет операцию получения всех местоположений. itemRepository.getAllLocations()
* @return Возвращает список местоположений со счетчиками. } catch (e: Exception) {
*/ // [ERROR_HANDLER] Просто возвращаем null.
suspend operator fun invoke(): List<LocationOutCount> { null
// [ACTION] }
return itemRepository.getAllLocations()
} }
} }
// [END_FILE_GetAllLocationsUseCase.kt] // [END_FILE_GetAllLocationsUseCase.kt]

View File

@@ -1,29 +1,25 @@
// [PACKAGE] com.homebox.lens.domain.usecase // [PACKAGE] com.homebox.lens.domain.usecase
// [FILE] GetStatisticsUseCase.kt // [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetStatisticsUseCase.kt
// [SEMANTICS] business_logic, use_case, statistics // [SEMANTICS] domain, usecase, statistics
// [IMPORTS] // [IMPORTS]
package com.homebox.lens.domain.usecase
import com.homebox.lens.domain.model.GroupStatistics import com.homebox.lens.domain.model.GroupStatistics
import com.homebox.lens.domain.repository.ItemRepository import com.homebox.lens.domain.repository.ItemRepository
import javax.inject.Inject import javax.inject.Inject
// [CORE-LOGIC] // [CORE-LOGIC]
/**
* [CONTRACT]
* Use case для получения статистики.
* @param itemRepository Репозиторий для работы с данными.
*/
class GetStatisticsUseCase @Inject constructor( class GetStatisticsUseCase @Inject constructor(
private val itemRepository: ItemRepository private val itemRepository: ItemRepository
) { ) {
/** suspend operator fun invoke(): GroupStatistics? {
* [CONTRACT] return try {
* Выполняет операцию получения статистики. itemRepository.getStatistics()
* @return Возвращает объект со статистикой. } catch (e: Exception) {
*/ // [ERROR_HANDLER] Просто возвращаем null, вызывающий слой обработает это.
suspend operator fun invoke(): GroupStatistics { null
// [ACTION] }
return itemRepository.getStatistics()
} }
} }
// [END_FILE_GetStatisticsUseCase.kt] // [END_FILE_GetStatisticsUseCase.kt]

View File

@@ -1,3 +1,5 @@
#[FILE] gradle.properties
#[PURPOSE] ????????? ??? ?????? Gradle
## For more details on how to configure your build environment visit ## For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# #
@@ -10,8 +12,15 @@
# This option should only be used with decoupled projects. For more details, visit # This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Tue Aug 05 16:05:40 MSK 2025 #Tue Aug 05 15:58:20 MSK 2025
android.enableJetifier=true distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
org.gradle.java.home=/usr/lib/jvm/java-25-openjdk-amd64
android.useAndroidX=true android.useAndroidX=true
org.gradle.java.installations.auto-download=true # [ACTION] ??????????? ???????????? ????? ?????? (heap size) ??? Gradle ?? 4 ??.
org.gradle.java.installations.repositories=foojay # ??? ?????????? ??? ?????????????? OutOfMemoryError ?? ?????? ???????? APK.
org.gradle.jvmargs=-Xmx4g