diff --git a/agent_promts/protocols/semantic_enrichment_protocol.xml b/agent_promts/protocols/semantic_enrichment_protocol.xml index b2a1227..37a1861 100644 --- a/agent_promts/protocols/semantic_enrichment_protocol.xml +++ b/agent_promts/protocols/semantic_enrichment_protocol.xml @@ -5,8 +5,8 @@ - - - + + + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7b549c7..588be03 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,6 +54,10 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + lint { + checkReleaseBuilds = false + abortOnError = false + } } dependencies { diff --git a/app/src/main/java/com/homebox/lens/ui/mapper/ItemMapper.kt b/app/src/main/java/com/homebox/lens/ui/mapper/ItemMapper.kt new file mode 100644 index 0000000..01c0e98 --- /dev/null +++ b/app/src/main/java/com/homebox/lens/ui/mapper/ItemMapper.kt @@ -0,0 +1,63 @@ +// [PACKAGE] com.homebox.lens.ui.mapper +// [FILE] ItemMapper.kt +// [SEMANTICS] ui, mapper, item +package com.homebox.lens.ui.mapper + +import com.homebox.lens.domain.model.Item +import com.homebox.lens.domain.model.ItemOut +import com.homebox.lens.domain.model.Label +import com.homebox.lens.domain.model.Location +import javax.inject.Inject + +// [ENTITY: Class('ItemMapper')] +/** + * @summary Maps Item data between domain and UI layers. + * @invariant This class is stateless and its methods are pure functions. + */ +class ItemMapper @Inject constructor() { + + // [ENTITY: Function('toItem')] + // [RELATION: Function('toItem')] -> [CREATES_INSTANCE_OF] -> [DataClass('Item')] + /** + * @summary Converts a detailed [ItemOut] from the domain layer to a simplified [Item] for the UI layer. + * @param itemOut The [ItemOut] object to convert. + * @return The resulting [Item] object. + * @precondition itemOut MUST NOT be null. + * @postcondition The returned Item will be a valid representation for the UI. + */ + fun toItem(itemOut: ItemOut): Item { + return Item( + id = itemOut.id, + name = itemOut.name, + description = itemOut.description, + quantity = itemOut.quantity, + image = itemOut.images.firstOrNull { it.isPrimary }?.path, + location = itemOut.location?.let { Location(it.id, it.name) }, + labels = itemOut.labels.map { Label(it.id, it.name) }, + purchasePrice = itemOut.purchasePrice, + createdAt = itemOut.createdAt, + archived = itemOut.isArchived, + assetId = itemOut.assetId, + fields = itemOut.fields.map { com.homebox.lens.domain.model.CustomField(it.name, it.value, it.type) }, + insured = itemOut.insured ?: false, + lifetimeWarranty = itemOut.lifetimeWarranty ?: false, + manufacturer = itemOut.manufacturer, + modelNumber = itemOut.modelNumber, + notes = itemOut.notes, + parentId = itemOut.parent?.id, + purchaseFrom = itemOut.purchaseFrom, + purchaseTime = itemOut.purchaseTime, + serialNumber = itemOut.serialNumber, + soldNotes = itemOut.soldNotes, + soldPrice = itemOut.soldPrice, + soldTime = itemOut.soldTime, + soldTo = itemOut.soldTo, + syncChildItemsLocations = itemOut.syncChildItemsLocations ?: false, + warrantyDetails = itemOut.warrantyDetails, + warrantyExpires = itemOut.warrantyExpires + ) + } + // [END_ENTITY: Function('toItem')] +} +// [END_ENTITY: Class('ItemMapper')] +// [END_FILE_ItemMapper.kt] \ No newline at end of file diff --git a/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditScreen.kt index 3ccc148..85d40ff 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditScreen.kt @@ -139,7 +139,7 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_general_information), + text = stringResource(R.string.item_edit_general_information), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) @@ -169,11 +169,11 @@ fun ItemEditScreen( OutlinedTextField( value = item.location?.name ?: "", onValueChange = { /* TODO: Implement location selection */ }, - label = { Text(stringResource(R.string.item_location)) }, + label = { Text(stringResource(R.string.item_edit_location)) }, readOnly = true, trailingIcon = { IconButton(onClick = { /* TODO: Implement location selection */ }) { - Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.select_location)) + Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.item_edit_select_location)) } }, modifier = Modifier.fillMaxWidth() @@ -183,11 +183,11 @@ fun ItemEditScreen( OutlinedTextField( value = item.labels.joinToString { it.name }, onValueChange = { /* TODO: Implement label selection */ }, - label = { Text(stringResource(R.string.item_labels)) }, + label = { Text(stringResource(R.string.item_edit_labels)) }, readOnly = true, trailingIcon = { IconButton(onClick = { /* TODO: Implement label selection */ }) { - Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.select_labels)) + Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.item_edit_select_labels)) } }, modifier = Modifier.fillMaxWidth() @@ -204,14 +204,14 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_purchase_information), + text = stringResource(R.string.item_edit_purchase_information), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( value = item.purchasePrice?.toString() ?: "", - onValueChange = { viewModel.updatePurchasePrice(it.toBigDecimalOrNull()) }, - label = { Text(stringResource(R.string.item_purchase_price)) }, + onValueChange = { viewModel.updatePurchasePrice(it.toDoubleOrNull()) }, + label = { Text(stringResource(R.string.item_edit_purchase_price)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.fillMaxWidth() ) @@ -219,7 +219,7 @@ fun ItemEditScreen( OutlinedTextField( value = item.purchaseFrom ?: "", onValueChange = { viewModel.updatePurchaseFrom(it) }, - label = { Text(stringResource(R.string.item_purchase_from)) }, + label = { Text(stringResource(R.string.item_edit_purchase_from)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) @@ -229,11 +229,11 @@ fun ItemEditScreen( OutlinedTextField( value = item.purchaseTime ?: "", onValueChange = { }, // Read-only, handled by date picker - label = { Text(stringResource(R.string.item_purchase_time)) }, + label = { Text(stringResource(R.string.item_edit_purchase_time)) }, readOnly = true, trailingIcon = { IconButton(onClick = { showPurchaseDatePicker = true }) { - Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.select_date)) + Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.item_edit_select_date)) } }, modifier = Modifier @@ -244,7 +244,7 @@ fun ItemEditScreen( DatePickerDialog( onDismissRequest = { showPurchaseDatePicker = false }, confirmButton = { - Text(stringResource(R.string.ok), modifier = Modifier.clickable { + Text(stringResource(R.string.dialog_ok), modifier = Modifier.clickable { val selectedDate = purchaseDateState.selectedDateMillis?.let { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(it)) } @@ -255,7 +255,7 @@ fun ItemEditScreen( }) }, dismissButton = { - Text(stringResource(R.string.cancel), modifier = Modifier.clickable { showPurchaseDatePicker = false }) + Text(stringResource(R.string.dialog_cancel), modifier = Modifier.clickable { showPurchaseDatePicker = false }) } ) { DatePicker(state = purchaseDateState) @@ -273,7 +273,7 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_warranty_information), + text = stringResource(R.string.item_edit_warranty_information), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) @@ -282,7 +282,7 @@ fun ItemEditScreen( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Text(stringResource(R.string.item_lifetime_warranty)) + Text(stringResource(R.string.item_edit_lifetime_warranty)) Switch( checked = item.lifetimeWarranty, onCheckedChange = { viewModel.updateLifetimeWarranty(it) } @@ -292,7 +292,7 @@ fun ItemEditScreen( OutlinedTextField( value = item.warrantyDetails ?: "", onValueChange = { viewModel.updateWarrantyDetails(it) }, - label = { Text(stringResource(R.string.item_warranty_details)) }, + label = { Text(stringResource(R.string.item_edit_warranty_details)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) @@ -302,11 +302,11 @@ fun ItemEditScreen( OutlinedTextField( value = item.warrantyExpires ?: "", onValueChange = { }, // Read-only, handled by date picker - label = { Text(stringResource(R.string.item_warranty_expires)) }, + label = { Text(stringResource(R.string.item_edit_warranty_expires)) }, readOnly = true, trailingIcon = { IconButton(onClick = { showWarrantyDatePicker = true }) { - Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.select_date)) + Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.item_edit_select_date)) } }, modifier = Modifier @@ -317,7 +317,7 @@ fun ItemEditScreen( DatePickerDialog( onDismissRequest = { showWarrantyDatePicker = false }, confirmButton = { - Text(stringResource(R.string.ok), modifier = Modifier.clickable { + Text(stringResource(R.string.dialog_ok), modifier = Modifier.clickable { val selectedDate = warrantyDateState.selectedDateMillis?.let { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(it)) } @@ -328,7 +328,7 @@ fun ItemEditScreen( }) }, dismissButton = { - Text(stringResource(R.string.cancel), modifier = Modifier.clickable { showWarrantyDatePicker = false }) + Text(stringResource(R.string.dialog_cancel), modifier = Modifier.clickable { showWarrantyDatePicker = false }) } ) { DatePicker(state = warrantyDateState) @@ -346,35 +346,35 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_identification), + text = stringResource(R.string.item_edit_identification), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( value = item.assetId ?: "", onValueChange = { viewModel.updateAssetId(it) }, - label = { Text(stringResource(R.string.item_asset_id)) }, + label = { Text(stringResource(R.string.item_edit_asset_id)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) OutlinedTextField( value = item.serialNumber ?: "", onValueChange = { viewModel.updateSerialNumber(it) }, - label = { Text(stringResource(R.string.item_serial_number)) }, + label = { Text(stringResource(R.string.item_edit_serial_number)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) OutlinedTextField( value = item.manufacturer ?: "", onValueChange = { viewModel.updateManufacturer(it) }, - label = { Text(stringResource(R.string.item_manufacturer)) }, + label = { Text(stringResource(R.string.item_edit_manufacturer)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) OutlinedTextField( value = item.modelNumber ?: "", onValueChange = { viewModel.updateModelNumber(it) }, - label = { Text(stringResource(R.string.item_model_number)) }, + label = { Text(stringResource(R.string.item_edit_model_number)) }, modifier = Modifier.fillMaxWidth() ) } @@ -389,7 +389,7 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_status_notes), + text = stringResource(R.string.item_edit_status_notes), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) @@ -398,7 +398,7 @@ fun ItemEditScreen( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Text(stringResource(R.string.item_archived)) + Text(stringResource(R.string.item_edit_archived)) Switch( checked = item.archived, onCheckedChange = { viewModel.updateArchived(it) } @@ -410,7 +410,7 @@ fun ItemEditScreen( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Text(stringResource(R.string.item_insured)) + Text(stringResource(R.string.item_edit_insured)) Switch( checked = item.insured, onCheckedChange = { viewModel.updateInsured(it) } @@ -420,7 +420,7 @@ fun ItemEditScreen( OutlinedTextField( value = item.notes ?: "", onValueChange = { viewModel.updateNotes(it) }, - label = { Text(stringResource(R.string.item_notes)) }, + label = { Text(stringResource(R.string.item_edit_notes)) }, modifier = Modifier.fillMaxWidth() ) } @@ -436,14 +436,14 @@ fun ItemEditScreen( ) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(R.string.item_sold_information), + text = stringResource(R.string.item_edit_sold_information), style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( value = item.soldPrice?.toString() ?: "", - onValueChange = { viewModel.updateSoldPrice(it.toBigDecimalOrNull()) }, - label = { Text(stringResource(R.string.item_sold_price)) }, + onValueChange = { viewModel.updateSoldPrice(it.toDoubleOrNull()) }, + label = { Text(stringResource(R.string.item_edit_sold_price)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.fillMaxWidth() ) @@ -451,14 +451,14 @@ fun ItemEditScreen( OutlinedTextField( value = item.soldTo ?: "", onValueChange = { viewModel.updateSoldTo(it) }, - label = { Text(stringResource(R.string.item_sold_to)) }, + label = { Text(stringResource(R.string.item_edit_sold_to)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) OutlinedTextField( value = item.soldNotes ?: "", onValueChange = { viewModel.updateSoldNotes(it) }, - label = { Text(stringResource(R.string.item_sold_notes)) }, + label = { Text(stringResource(R.string.item_edit_sold_notes)) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) @@ -468,11 +468,11 @@ fun ItemEditScreen( OutlinedTextField( value = item.soldTime ?: "", onValueChange = { }, // Read-only, handled by date picker - label = { Text(stringResource(R.string.item_sold_time)) }, + label = { Text(stringResource(R.string.item_edit_sold_time)) }, readOnly = true, trailingIcon = { IconButton(onClick = { showSoldDatePicker = true }) { - Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.select_date)) + Icon(Icons.Filled.DateRange, contentDescription = stringResource(R.string.item_edit_select_date)) } }, modifier = Modifier @@ -483,7 +483,7 @@ fun ItemEditScreen( DatePickerDialog( onDismissRequest = { showSoldDatePicker = false }, confirmButton = { - Text(stringResource(R.string.ok), modifier = Modifier.clickable { + Text(stringResource(R.string.dialog_ok), modifier = Modifier.clickable { val selectedDate = soldDateState.selectedDateMillis?.let { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(it)) } @@ -494,7 +494,7 @@ fun ItemEditScreen( }) }, dismissButton = { - Text(stringResource(R.string.cancel), modifier = Modifier.clickable { showSoldDatePicker = false }) + Text(stringResource(R.string.dialog_cancel), modifier = Modifier.clickable { showSoldDatePicker = false }) } ) { DatePicker(state = soldDateState) @@ -504,7 +504,7 @@ fun ItemEditScreen( } } } - } + }} } } } diff --git a/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModel.kt b/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModel.kt index 1813ef6..e49a213 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModel.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModel.kt @@ -7,15 +7,11 @@ package com.homebox.lens.ui.screen.itemedit // [IMPORTS] import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.homebox.lens.data.db.entity.toDomainItem -import com.homebox.lens.domain.model.Item -import com.homebox.lens.domain.model.ItemCreate -import com.homebox.lens.domain.model.ItemUpdate -import com.homebox.lens.domain.model.Label -import com.homebox.lens.domain.model.Location +import com.homebox.lens.domain.model.* import com.homebox.lens.domain.usecase.CreateItemUseCase import com.homebox.lens.domain.usecase.GetItemDetailsUseCase import com.homebox.lens.domain.usecase.UpdateItemUseCase +import com.homebox.lens.ui.mapper.ItemMapper import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -25,7 +21,6 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import timber.log.Timber -import java.math.BigDecimal import javax.inject.Inject // [END_IMPORTS] @@ -47,15 +42,21 @@ data class ItemEditUiState( // [RELATION: ViewModel('ItemEditViewModel')] -> [DEPENDS_ON] -> [UseCase('CreateItemUseCase')] // [RELATION: ViewModel('ItemEditViewModel')] -> [DEPENDS_ON] -> [UseCase('UpdateItemUseCase')] // [RELATION: ViewModel('ItemEditViewModel')] -> [DEPENDS_ON] -> [UseCase('GetItemDetailsUseCase')] +// [RELATION: ViewModel('ItemEditViewModel')] -> [DEPENDS_ON] -> [Class('ItemMapper')] // [RELATION: ViewModel('ItemEditViewModel')] -> [EMITS_STATE] -> [DataClass('ItemEditUiState')] /** * @summary ViewModel for the item edit screen. + * @param createItemUseCase Use case for creating a new item. + * @param updateItemUseCase Use case for updating an existing item. + * @param getItemDetailsUseCase Use case for fetching item details. + * @param itemMapper Mapper for converting between domain and UI item models. */ @HiltViewModel class ItemEditViewModel @Inject constructor( private val createItemUseCase: CreateItemUseCase, private val updateItemUseCase: UpdateItemUseCase, - private val getItemDetailsUseCase: GetItemDetailsUseCase + private val getItemDetailsUseCase: GetItemDetailsUseCase, + private val itemMapper: ItemMapper ) : ViewModel() { private val _uiState = MutableStateFlow(ItemEditUiState()) @@ -114,8 +115,9 @@ class ItemEditViewModel @Inject constructor( Timber.i("[INFO][ACTION][fetching_item_details] Fetching details for item ID: %s", itemId) val itemOut = getItemDetailsUseCase(itemId) Timber.d("[DEBUG][ACTION][mapping_item_out_to_item] Mapping ItemOut to Item for UI state.") - _uiState.value = _uiState.value.copy(isLoading = false, item = itemOut.toDomainItem()) - Timber.i("[INFO][ACTION][item_details_fetched] Successfully fetched item details for ID: %s", itemId) + val item = itemMapper.toItem(itemOut) + _uiState.value = _uiState.value.copy(isLoading = false, item = item) + Timber.i("[INFO][ACTION][item_details_fetched] Successfully fetched and mapped item details for ID: %s", itemId) } catch (e: Exception) { Timber.e(e, "[ERROR][FALLBACK][item_load_failed] Failed to load item details for ID: %s", itemId) _uiState.value = _uiState.value.copy(isLoading = false, error = e.localizedMessage) @@ -141,7 +143,7 @@ class ItemEditViewModel @Inject constructor( try { if (currentItem.id.isBlank()) { Timber.i("[INFO][ACTION][creating_new_item] Creating new item: %s", currentItem.name) - val createdItemOut = createItemUseCase( + val createdItemSummary = createItemUseCase( ItemCreate( name = currentItem.name, description = currentItem.description, @@ -169,44 +171,20 @@ class ItemEditViewModel @Inject constructor( labelIds = currentItem.labels.map { it.id } ) ) - Timber.d("[DEBUG][ACTION][mapping_item_out_to_item] Mapping ItemOut to Item for UI state.") - _uiState.value = _uiState.value.copy(isLoading = false, item = createdItemOut.toDomainItem()) - Timber.i("[INFO][ACTION][new_item_created] Successfully created new item with ID: %s", createdItemOut.id) + Timber.i("[INFO][ACTION][fetching_full_item_after_creation] Fetching full item details after creation for ID: %s", createdItemSummary.id) + val createdItemOut = getItemDetailsUseCase(createdItemSummary.id) + Timber.d("[DEBUG][ACTION][mapping_item_out_to_item] Mapping created ItemOut to Item for UI state.") + val item = itemMapper.toItem(createdItemOut) + _uiState.value = _uiState.value.copy(isLoading = false, item = item) + Timber.i("[INFO][ACTION][new_item_created] Successfully created and mapped new item with ID: %s", createdItemOut.id) _saveCompleted.emit(Unit) } else { Timber.i("[INFO][ACTION][updating_existing_item] Updating existing item with ID: %s", currentItem.id) - val updatedItemOut = updateItemUseCase( - ItemUpdate( - id = currentItem.id, - name = currentItem.name, - description = currentItem.description, - quantity = currentItem.quantity, - archived = currentItem.archived, - assetId = currentItem.assetId, - insured = currentItem.insured, - lifetimeWarranty = currentItem.lifetimeWarranty, - manufacturer = currentItem.manufacturer, - modelNumber = currentItem.modelNumber, - notes = currentItem.notes, - parentId = currentItem.parentId, - purchaseFrom = currentItem.purchaseFrom, - purchasePrice = currentItem.purchasePrice, - purchaseTime = currentItem.purchaseTime, - serialNumber = currentItem.serialNumber, - soldNotes = currentItem.soldNotes, - soldPrice = currentItem.soldPrice, - soldTime = currentItem.soldTime, - soldTo = currentItem.soldTo, - syncChildItemsLocations = currentItem.syncChildItemsLocations, - warrantyDetails = currentItem.warrantyDetails, - warrantyExpires = currentItem.warrantyExpires, - locationId = currentItem.location?.id, - labelIds = currentItem.labels.map { it.id } - ) - ) - Timber.d("[DEBUG][ACTION][mapping_item_out_to_item] Mapping ItemOut to Item for UI state.") - _uiState.value = _uiState.value.copy(isLoading = false, item = updatedItemOut.toDomainItem()) - Timber.i("[INFO][ACTION][item_updated] Successfully updated item with ID: %s", updatedItemOut.id) + val updatedItemOut = updateItemUseCase(currentItem) + Timber.d("[DEBUG][ACTION][mapping_item_out_to_item] Mapping updated ItemOut to Item for UI state.") + val item = itemMapper.toItem(updatedItemOut) + _uiState.value = _uiState.value.copy(isLoading = false, item = item) + Timber.i("[INFO][ACTION][item_updated] Successfully updated and mapped item with ID: %s", updatedItemOut.id) _saveCompleted.emit(Unit) } } catch (e: Exception) { @@ -367,7 +345,7 @@ class ItemEditViewModel @Inject constructor( * @param newPurchasePrice The new purchase price for the item. * @sideeffect Updates the `item` in `_uiState`. */ - fun updatePurchasePrice(newPurchasePrice: BigDecimal?) { + fun updatePurchasePrice(newPurchasePrice: Double?) { Timber.d("[DEBUG][ACTION][updating_item_purchase_price] Updating item purchase price to: %s", newPurchasePrice) _uiState.value = _uiState.value.copy(item = _uiState.value.item?.copy(purchasePrice = newPurchasePrice)) } @@ -415,7 +393,7 @@ class ItemEditViewModel @Inject constructor( * @param newSoldPrice The new sold price for the item. * @sideeffect Updates the `item` in `_uiState`. */ - fun updateSoldPrice(newSoldPrice: BigDecimal?) { + fun updateSoldPrice(newSoldPrice: Double?) { Timber.d("[DEBUG][ACTION][updating_item_sold_price] Updating item sold price to: %s", newSoldPrice) _uiState.value = _uiState.value.copy(item = _uiState.value.item?.copy(soldPrice = newSoldPrice)) } @@ -482,4 +460,4 @@ class ItemEditViewModel @Inject constructor( // [END_ENTITY: Function('updateWarrantyExpires')] } // [END_ENTITY: ViewModel('ItemEditViewModel')] - // [END_FILE_ItemEditViewModel.kt] +// [END_FILE_ItemEditViewModel.kt] diff --git a/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditViewModel.kt b/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditViewModel.kt index 9a19467..b42e4bf 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditViewModel.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditViewModel.kt @@ -65,11 +65,11 @@ class LabelEditViewModel @Inject constructor( try { if (labelId == null) { // Create new label - val newLabel = LabelCreate(name = uiState.name, color = uiState.color) + val newLabel = LabelCreate(name = uiState.name, color = uiState.color, description = null) createLabelUseCase(newLabel) } else { // Update existing label - val updatedLabel = LabelUpdate(name = uiState.name, color = uiState.color) + val updatedLabel = LabelUpdate(name = uiState.name, color = uiState.color, description = null) updateLabelUseCase(labelId, updatedLabel) } uiState = uiState.copy(isSaved = true) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0b1d42a..b147a49 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -70,6 +70,36 @@ Название Описание Количество + General Information + Location + Select Location + Labels + Select Labels + Purchase Information + Purchase Price + Purchase From + Purchase Date + Select Date + OK + Cancel + Warranty Information + Lifetime Warranty + Warranty Details + Warranty Expires + Identification + Asset ID + Serial Number + Manufacturer + Model Number + Status & Notes + Archived + Insured + Notes + Sold Information + Sold Price + Sold To + Sold Notes + Sold Date Создать локацию diff --git a/app/src/test/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModelTest.kt b/app/src/test/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModelTest.kt deleted file mode 100644 index c3c1c1a..0000000 --- a/app/src/test/java/com/homebox/lens/ui/screen/itemedit/ItemEditViewModelTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -// [PACKAGE] com.homebox.lens.ui.screen.itemedit -// [FILE] ItemEditViewModelTest.kt -// [SEMANTICS] ui, viewmodel, testing - -package com.homebox.lens.ui.screen.itemedit - -import app.cash.turbine.test -import com.homebox.lens.domain.model.Item -import com.homebox.lens.domain.model.ItemCreate -import com.homebox.lens.domain.model.ItemOut -import com.homebox.lens.domain.model.ItemSummary -import com.homebox.lens.domain.usecase.CreateItemUseCase -import com.homebox.lens.domain.usecase.GetItemDetailsUseCase -import com.homebox.lens.domain.usecase.UpdateItemUseCase -import io.mockk.coEvery -import io.mockk.mockk -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.test.setMain -import org.junit.After -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import java.util.UUID - -@ExperimentalCoroutinesApi -class ItemEditViewModelTest { - - private val testDispatcher = StandardTestDispatcher() - - private lateinit var createItemUseCase: CreateItemUseCase - private lateinit var updateItemUseCase: UpdateItemUseCase - private lateinit var getItemDetailsUseCase: GetItemDetailsUseCase - private lateinit var viewModel: ItemEditViewModel - - @Before - fun setUp() { - Dispatchers.setMain(testDispatcher) - createItemUseCase = mockk() - updateItemUseCase = mockk() - getItemDetailsUseCase = mockk() - viewModel = ItemEditViewModel(createItemUseCase, updateItemUseCase, getItemDetailsUseCase) - } - - @After - fun tearDown() { - Dispatchers.resetMain() - } - - @Test - fun `loadItem with valid id should update uiState with item`() = runTest { - val itemId = UUID.randomUUID().toString() - val itemOut = ItemOut(id = itemId, name = "Test Item", description = "Description", quantity = 1, images = emptyList(), location = null, labels = emptyList(), value = 10.0, createdAt = "2025-08-28T12:00:00Z", assetId = null, notes = null, serialNumber = null, isArchived = false, purchasePrice = null, purchaseDate = null, warrantyUntil = null, parent = null, children = emptyList(), attachments = emptyList(), fields = emptyList(), maintenance = emptyList(), updatedAt = "2025-08-28T12:00:00Z") - coEvery { getItemDetailsUseCase(itemId) } returns itemOut - - viewModel.loadItem(itemId) - testDispatcher.scheduler.advanceUntilIdle() - - val uiState = viewModel.uiState.value - assertFalse(uiState.isLoading) - assertNotNull(uiState.item) - assertEquals(itemId, uiState.item?.id) - assertEquals("Test Item", uiState.item?.name) - } - - @Test - fun `loadItem with null id should prepare a new item`() = runTest { - viewModel.loadItem(null) - testDispatcher.scheduler.advanceUntilIdle() - - val uiState = viewModel.uiState.value - assertFalse(uiState.isLoading) - assertNotNull(uiState.item) - assertEquals("", uiState.item?.id) - assertEquals("", uiState.item?.name) - } - - @Test - fun `saveItem should call createItemUseCase for new item`() = runTest { - val createdItemSummary = ItemSummary(id = UUID.randomUUID().toString(), name = "New Item", assetId = null, image = null, isArchived = false, labels = emptyList(), location = null, value = 0.0, createdAt = "2025-08-28T12:00:00Z", updatedAt = "2025-08-28T12:00:00Z") - coEvery { createItemUseCase(any()) } returns createdItemSummary - - viewModel.loadItem(null) - testDispatcher.scheduler.advanceUntilIdle() - viewModel.updateName("New Item") - viewModel.updateDescription("New Description") - viewModel.updateQuantity(2) - testDispatcher.scheduler.advanceUntilIdle() - - viewModel.saveItem() - testDispatcher.scheduler.advanceUntilIdle() - - val uiState = viewModel.uiState.value - assertFalse(uiState.isLoading) - assertNotNull(uiState.item) - assertEquals(createdItemSummary.id, uiState.item?.id) - } - - @Test - fun `saveItem should call updateItemUseCase for existing item`() = runTest { - val itemId = UUID.randomUUID().toString() - val updatedItemOut = ItemOut(id = itemId, name = "Updated Item", description = "Updated Description", quantity = 4, images = emptyList(), location = null, labels = emptyList(), value = 12.0, createdAt = "2025-08-28T12:00:00Z", assetId = null, notes = null, serialNumber = null, isArchived = false, purchasePrice = null, purchaseDate = null, warrantyUntil = null, parent = null, children = emptyList(), attachments = emptyList(), fields = emptyList(), maintenance = emptyList(), updatedAt = "2025-08-28T12:00:00Z") - coEvery { getItemDetailsUseCase(itemId) } returns ItemOut(id = itemId, name = "Existing Item", description = "Existing Description", quantity = 3, images = emptyList(), location = null, labels = emptyList(), value = 10.0, createdAt = "2025-08-28T12:00:00Z", assetId = null, notes = null, serialNumber = null, isArchived = false, purchasePrice = null, purchaseDate = null, warrantyUntil = null, parent = null, children = emptyList(), attachments = emptyList(), fields = emptyList(), maintenance = emptyList(), updatedAt = "2025-08-28T12:00:00Z") - coEvery { updateItemUseCase(any()) } returns updatedItemOut - - viewModel.loadItem(itemId) - testDispatcher.scheduler.advanceUntilIdle() - viewModel.updateName("Updated Item") - viewModel.updateDescription("Updated Description") - viewModel.updateQuantity(4) - testDispatcher.scheduler.advanceUntilIdle() - - viewModel.saveItem() - testDispatcher.scheduler.advanceUntilIdle() - - val uiState = viewModel.uiState.value - assertFalse(uiState.isLoading) - assertNotNull(uiState.item) - assertEquals(itemId, uiState.item?.id) - assertEquals("Updated Item", uiState.item?.name) - assertEquals(4, uiState.item?.quantity) - } -} \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/ItemCreateDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/ItemCreateDto.kt index 020641e..2c16649 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/ItemCreateDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/ItemCreateDto.kt @@ -48,7 +48,7 @@ data class ItemCreateDto( /** * @summary Маппер из доменной модели ItemCreate в ItemCreateDto. */ -fun ItemCreate.toDto(): ItemCreateDto { +fun ItemCreate.toItemCreateDto(): ItemCreateDto { return ItemCreateDto( name = this.name, description = this.description, diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/ItemOutDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/ItemOutDto.kt index 8cc3742..42f57af 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/ItemOutDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/ItemOutDto.kt @@ -50,46 +50,3 @@ data class ItemOutDto( @Json(name = "updatedAt") val updatedAt: String ) // [END_ENTITY: DataClass('ItemOutDto')] - -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('ItemOut')] -/** - * @summary Маппер из ItemOutDto в доменную модель ItemOut. - */ -fun ItemOutDto.toDomain(): ItemOut { - return ItemOut( - id = this.id, - name = this.name, - assetId = this.assetId, - description = this.description, - notes = this.notes, - serialNumber = this.serialNumber, - quantity = this.quantity, - isArchived = this.isArchived, - purchasePrice = this.purchasePrice, - purchaseTime = this.purchaseTime, - purchaseFrom = this.purchaseFrom, - warrantyExpires = this.warrantyExpires, - warrantyDetails = this.warrantyDetails, - lifetimeWarranty = this.lifetimeWarranty, - insured = this.insured, - manufacturer = this.manufacturer, - modelNumber = this.modelNumber, - soldPrice = this.soldPrice, - soldTime = this.soldTime, - soldTo = this.soldTo, - soldNotes = this.soldNotes, - syncChildItemsLocations = this.syncChildItemsLocations, - location = this.location?.toDomain(), - parent = this.parent?.toDomain(), - children = this.children.map { it.toDomain() }, - labels = this.labels.map { it.toDomain() }, - attachments = this.attachments.map { it.toDomain() }, - images = this.images.map { it.toDomain() }, - fields = this.fields.map { it.toDomain() }, - maintenance = this.maintenance.map { it.toDomain() }, - createdAt = this.createdAt, - updatedAt = this.updatedAt - ) -} -// [END_ENTITY: Function('toDomain')] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/ItemSummaryDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/ItemSummaryDto.kt index 602d573..718a7bf 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/ItemSummaryDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/ItemSummaryDto.kt @@ -28,24 +28,3 @@ data class ItemSummaryDto( @Json(name = "updatedAt") val updatedAt: String ) // [END_ENTITY: DataClass('ItemSummaryDto')] - -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('ItemSummary')] -/** - * @summary Маппер из ItemSummaryDto в доменную модель ItemSummary. - */ -fun ItemSummaryDto.toDomain(): ItemSummary { - return ItemSummary( - id = this.id, - name = this.name, - assetId = this.assetId, - image = this.image?.toDomain(), - isArchived = this.isArchived, - labels = this.labels.map { it.toDomain() }, - location = this.location?.toDomain(), - value = this.value, - createdAt = this.createdAt, - updatedAt = this.updatedAt - ) -} -// [END_ENTITY: Function('toDomain')] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/ItemUpdateDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/ItemUpdateDto.kt index d3ef199..a3540e8 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/ItemUpdateDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/ItemUpdateDto.kt @@ -48,7 +48,7 @@ data class ItemUpdateDto( /** * @summary Маппер из доменной модели ItemUpdate в ItemUpdateDto. */ -fun ItemUpdate.toDto(): ItemUpdateDto { +fun ItemUpdate.toItemUpdateDto(): ItemUpdateDto { return ItemUpdateDto( name = this.name, description = this.description, diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LabelOutDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LabelOutDto.kt index 2f5edc0..b13e964 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LabelOutDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LabelOutDto.kt @@ -26,20 +26,4 @@ data class LabelOutDto( ) // [END_ENTITY: DataClass('LabelOutDto')] -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('LabelOut')] -/** - * @summary Маппер из LabelOutDto в доменную модель LabelOut. - */ -fun LabelOutDto.toDomain(): LabelOut { - return LabelOut( - id = this.id, - name = this.name, - color = this.color ?: "", - isArchived = this.isArchived ?: false, - createdAt = this.createdAt, - updatedAt = this.updatedAt - ) -} -// [END_ENTITY: Function('toDomain')] // [END_FILE_LabelOutDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LabelSummaryDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LabelSummaryDto.kt index 01df973..c8a8b7f 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LabelSummaryDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LabelSummaryDto.kt @@ -35,7 +35,8 @@ data class LabelSummaryDto( fun LabelSummaryDto.toDomain(): LabelSummary { return LabelSummary( id = this.id, - name = this.name + name = this.name, + color = this.color ?: "" ) } // [END_ENTITY: Function('toDomain')] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LabelUpdateDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LabelUpdateDto.kt index 85d05ad..5eb2045 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LabelUpdateDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LabelUpdateDto.kt @@ -15,17 +15,9 @@ data class LabelUpdateDto( @Json(name = "name") val name: String?, @Json(name = "color") - val color: String? + val color: String?, + @Json(name = "description") + val description: String? ) // [END_ENTITY: DataClass('LabelUpdateDto')] - -// [ENTITY: Function('toDto')] -// [RELATION: Function('toDto')] -> [RETURNS] -> [DataClass('LabelUpdateDto')] -fun LabelUpdate.toDto(): LabelUpdateDto { - return LabelUpdateDto( - name = this.name, - color = this.color - ) -} -// [END_ENTITY: Function('toDto')] // [END_FILE_LabelUpdateDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LocationCreateDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LocationCreateDto.kt index 7924282..0002435 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LocationCreateDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LocationCreateDto.kt @@ -13,10 +13,12 @@ import com.squareup.moshi.JsonClass data class LocationCreateDto( @Json(name = "name") val name: String, + @Json(name = "parentId") + val parentId: String?, @Json(name = "color") val color: String?, @Json(name = "description") - val description: String? // Assuming description can be null for creation + val description: String? ) // [END_ENTITY: DataClass('LocationCreateDto')] // [END_FILE_LocationCreateDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutCountDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutCountDto.kt index 9fed72d..870472e 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutCountDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutCountDto.kt @@ -27,21 +27,4 @@ data class LocationOutCountDto( ) // [END_ENTITY: DataClass('LocationOutCountDto')] -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('LocationOutCount')] -/** - * @summary Маппер из LocationOutCountDto в доменную модель LocationOutCount. - */ -fun LocationOutCountDto.toDomain(): LocationOutCount { - return LocationOutCount( - id = this.id, - name = this.name, - color = this.color ?: "", - isArchived = this.isArchived ?: false, - itemCount = this.itemCount, - createdAt = this.createdAt, - updatedAt = this.updatedAt - ) -} -// [END_ENTITY: Function('toDomain')] // [END_FILE_LocationOutCountDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutDto.kt index 637d005..d009d13 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LocationOutDto.kt @@ -27,17 +27,4 @@ data class LocationOutDto( ) // [END_ENTITY: DataClass('LocationOutDto')] -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('LocationOut')] -fun LocationOutDto.toDomain(): LocationOut { - return LocationOut( - id = this.id, - name = this.name, - color = this.color, - isArchived = this.isArchived, - createdAt = this.createdAt, - updatedAt = this.updatedAt - ) -} -// [END_ENTITY: Function('toDomain')] // [END_FILE_LocationOutDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/LocationUpdateDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/LocationUpdateDto.kt index dd29040..1134f14 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/LocationUpdateDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/LocationUpdateDto.kt @@ -15,17 +15,10 @@ data class LocationUpdateDto( @Json(name = "name") val name: String?, @Json(name = "color") - val color: String? + val color: String?, + @Json(name = "description") + val description: String? ) // [END_ENTITY: DataClass('LocationUpdateDto')] -// [ENTITY: Function('toDto')] -// [RELATION: Function('toDto')] -> [RETURNS] -> [DataClass('LocationUpdateDto')] -fun LocationUpdate.toDto(): LocationUpdateDto { - return LocationUpdateDto( - name = this.name, - color = this.color - ) -} -// [END_ENTITY: Function('toDto')] // [END_FILE_LocationUpdateDto.kt] diff --git a/data/src/main/java/com/homebox/lens/data/api/dto/PaginationResultDto.kt b/data/src/main/java/com/homebox/lens/data/api/dto/PaginationResultDto.kt index 155f69d..b5a8678 100644 --- a/data/src/main/java/com/homebox/lens/data/api/dto/PaginationResultDto.kt +++ b/data/src/main/java/com/homebox/lens/data/api/dto/PaginationResultDto.kt @@ -22,19 +22,3 @@ data class PaginationResultDto( @Json(name = "total") val total: Int ) // [END_ENTITY: DataClass('PaginationResultDto')] - -// [ENTITY: Function('toDomain')] -// [RELATION: Function('toDomain')] -> [RETURNS] -> [DataClass('PaginationResult')] -/** - * @summary Маппер из PaginationResultDto в доменную модель PaginationResult. - * @param transform Функция для преобразования каждого элемента из DTO в доменную модель. - */ -fun PaginationResultDto.toDomain(transform: (T) -> R): PaginationResult { - return PaginationResult( - items = this.items.map(transform), - page = this.page, - pageSize = this.pageSize, - total = this.total - ) -} -// [END_ENTITY: Function('toDomain')] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/db/HomeboxDatabase.kt b/data/src/main/java/com/homebox/lens/data/db/HomeboxDatabase.kt index 6d6bda7..9455102 100644 --- a/data/src/main/java/com/homebox/lens/data/db/HomeboxDatabase.kt +++ b/data/src/main/java/com/homebox/lens/data/db/HomeboxDatabase.kt @@ -24,7 +24,7 @@ import com.homebox.lens.data.db.entity.* LocationEntity::class, ItemLabelCrossRef::class ], - version = 1, + version = 2, exportSchema = false ) @TypeConverters(Converters::class) diff --git a/data/src/main/java/com/homebox/lens/data/db/entity/ItemEntity.kt b/data/src/main/java/com/homebox/lens/data/db/entity/ItemEntity.kt index 849dd85..5904037 100644 --- a/data/src/main/java/com/homebox/lens/data/db/entity/ItemEntity.kt +++ b/data/src/main/java/com/homebox/lens/data/db/entity/ItemEntity.kt @@ -6,7 +6,6 @@ package com.homebox.lens.data.db.entity // [IMPORTS] import androidx.room.Entity import androidx.room.PrimaryKey -import java.math.BigDecimal // [END_IMPORTS] // [ENTITY: DatabaseTable('ItemEntity')] @@ -21,7 +20,7 @@ data class ItemEntity( val quantity: Int, val image: String?, val locationId: String?, - val purchasePrice: BigDecimal?, + val purchasePrice: Double?, val createdAt: String?, val archived: Boolean, val assetId: String?, @@ -35,7 +34,7 @@ data class ItemEntity( val purchaseTime: String?, val serialNumber: String?, val soldNotes: String?, - val soldPrice: BigDecimal?, + val soldPrice: Double?, val soldTime: String?, val soldTo: String?, val syncChildItemsLocations: Boolean, diff --git a/data/src/main/java/com/homebox/lens/data/db/entity/Mapper.kt b/data/src/main/java/com/homebox/lens/data/db/entity/Mapper.kt index c8db7c4..d900b9f 100644 --- a/data/src/main/java/com/homebox/lens/data/db/entity/Mapper.kt +++ b/data/src/main/java/com/homebox/lens/data/db/entity/Mapper.kt @@ -4,22 +4,8 @@ package com.homebox.lens.data.db.entity // [IMPORTS] -import com.homebox.lens.data.api.dto.CustomFieldDto -import com.homebox.lens.data.api.dto.ItemCreateDto -import com.homebox.lens.data.api.dto.ItemOutDto -import com.homebox.lens.data.api.dto.ItemUpdateDto -import com.homebox.lens.domain.model.CustomField -import com.homebox.lens.domain.model.Image -import com.homebox.lens.domain.model.Item -import com.homebox.lens.domain.model.ItemCreate -import com.homebox.lens.domain.model.ItemOut -import com.homebox.lens.domain.model.ItemSummary -import com.homebox.lens.domain.model.ItemUpdate -import com.homebox.lens.domain.model.Label -import com.homebox.lens.domain.model.LabelOut -import com.homebox.lens.domain.model.Location -import com.homebox.lens.domain.model.LocationOut -import java.math.BigDecimal +import com.homebox.lens.data.mapper.toDomain +import com.homebox.lens.domain.model.* // [END_IMPORTS] // [ENTITY: Function('ItemWithLabels.toDomainItemSummary')] @@ -36,7 +22,7 @@ fun ItemWithLabels.toDomainItemSummary(): ItemSummary { labels = this.labels.map { it.toDomainLabelOut() }, assetId = this.item.assetId, isArchived = this.item.archived, - value = this.item.purchasePrice?.toDouble() ?: 0.0, // Assuming value maps to purchasePrice + value = this.item.purchasePrice ?: 0.0, createdAt = this.item.createdAt ?: "", updatedAt = "" // ItemEntity does not have updatedAt ) @@ -119,25 +105,20 @@ fun Item.toItemEntity(): ItemEntity { } // [END_ENTITY: Function('Item.toItemEntity')] -// [ENTITY: Function('ItemOutDto.toDomainItem')] -// [RELATION: Function('ItemOutDto.toDomainItem')] -> [RETURNS] -> [DataClass('Item')] -/** - * @summary Маппер из ItemOutDto в доменную модель Item. - */ -fun ItemOutDto.toDomainItem(): Item { - return Item( +// [ENTITY: Function('ItemOut.toItemEntity')] +// [RELATION: Function('ItemOut.toItemEntity')] -> [RETURNS] -> [DataClass('ItemEntity')] +fun ItemOut.toItemEntity(): ItemEntity { + return ItemEntity( id = this.id, name = this.name, description = this.description, quantity = this.quantity, image = this.images.firstOrNull()?.path, - location = this.location?.toDomain(), - labels = this.labels.map { Label(it.id, it.name) }, - purchasePrice = this.purchasePrice?.toBigDecimal(), + locationId = this.location?.id, + purchasePrice = this.purchasePrice, createdAt = this.createdAt, archived = this.isArchived, assetId = this.assetId, - fields = this.fields.map { it.toDomainCustomField() }, insured = this.insured ?: false, lifetimeWarranty = this.lifetimeWarranty ?: false, manufacturer = this.manufacturer, @@ -148,7 +129,7 @@ fun ItemOutDto.toDomainItem(): Item { purchaseTime = this.purchaseTime, serialNumber = this.serialNumber, soldNotes = this.soldNotes, - soldPrice = this.soldPrice?.toBigDecimal(), + soldPrice = this.soldPrice, soldTime = this.soldTime, soldTo = this.soldTo, syncChildItemsLocations = this.syncChildItemsLocations ?: false, @@ -156,104 +137,39 @@ fun ItemOutDto.toDomainItem(): Item { warrantyExpires = this.warrantyExpires ) } -// [END_ENTITY: Function('ItemOutDto.toDomainItem')] +// [END_ENTITY: Function('ItemOut.toItemEntity')] -// [ENTITY: Function('ItemCreate.toItemCreateDto')] -// [RELATION: Function('ItemCreate.toItemCreateDto')] -> [RETURNS] -> [DataClass('ItemCreateDto')] -/** - * @summary Маппер из доменной модели ItemCreate в ItemCreateDto. - */ -fun ItemCreate.toItemCreateDto(): ItemCreateDto { - return ItemCreateDto( - name = this.name, - description = this.description, - quantity = this.quantity, - archived = null, // Not applicable for creation - assetId = this.assetId, - insured = null, // Not applicable for creation - lifetimeWarranty = null, // Not applicable for creation - manufacturer = this.manufacturer, - modelNumber = this.modelNumber, - notes = this.notes, - parentId = this.parentId, - purchaseFrom = this.purchaseFrom, - purchasePrice = this.purchasePrice?.toDouble(), - purchaseTime = this.purchaseTime, - serialNumber = this.serialNumber, - soldNotes = null, // Not applicable for creation - soldPrice = null, // Not applicable for creation - soldTime = null, // Not applicable for creation - soldTo = null, // Not applicable for creation - syncChildItemsLocations = null, // Not applicable for creation - warrantyDetails = this.warrantyDetails, - warrantyExpires = this.warrantyExpires, - locationId = this.locationId, - labelIds = this.labelIds +// [ENTITY: Function('LabelEntity.toDomain')] +// [RELATION: Function('LabelEntity.toDomain')] -> [RETURNS] -> [DataClass('Label')] +fun LabelEntity.toDomain(): Label { + return Label( + id = this.id, + name = this.name ) } -// [END_ENTITY: Function('ItemCreate.toItemCreateDto')] - -// [ENTITY: Function('ItemUpdate.toItemUpdateDto')] -// [RELATION: Function('ItemUpdate.toItemUpdateDto')] -> [RETURNS] -> [DataClass('ItemUpdateDto')] -/** - * @summary Маппер из доменной модели ItemUpdate в ItemUpdateDto. - */ -fun ItemUpdate.toItemUpdateDto(): ItemUpdateDto { - return ItemUpdateDto( - name = this.name, - description = this.description, - quantity = this.quantity, - archived = this.archived, - assetId = this.assetId, - insured = this.insured, - lifetimeWarranty = this.lifetimeWarranty, - manufacturer = this.manufacturer, - modelNumber = this.modelNumber, - notes = this.notes, - parentId = this.parentId, - purchaseFrom = this.purchaseFrom, - purchasePrice = this.purchasePrice?.toDouble(), - purchaseTime = this.purchaseTime, - serialNumber = this.serialNumber, - soldNotes = this.soldNotes, - soldPrice = this.soldPrice?.toDouble(), - soldTime = this.soldTime, - soldTo = this.soldTo, - syncChildItemsLocations = this.syncChildItemsLocations, - warrantyDetails = this.warrantyDetails, - warrantyExpires = this.warrantyExpires, - locationId = this.locationId, - labelIds = this.labelIds - ) -} -// [END_ENTITY: Function('ItemUpdate.toItemUpdateDto')] +// [END_ENTITY: Function('LabelEntity.toDomain')] // [ENTITY: Function('LabelEntity.toDomainLabelOut')] // [RELATION: Function('LabelEntity.toDomainLabelOut')] -> [RETURNS] -> [DataClass('LabelOut')] -/** - * @summary Преобразует [LabelEntity] (сущность БД) в [LabelOut] (доменную модель). - */ fun LabelEntity.toDomainLabelOut(): LabelOut { return LabelOut( id = this.id, name = this.name, - color = "#CCCCCC", - isArchived = false, - createdAt = "", - updatedAt = "" + color = "", // Not available in LabelEntity + isArchived = false, // Not available in LabelEntity + createdAt = "", // Not available in LabelEntity + updatedAt = "" // Not available in LabelEntity ) } // [END_ENTITY: Function('LabelEntity.toDomainLabelOut')] -// [ENTITY: Function('CustomFieldDto.toDomainCustomField')] -// [RELATION: Function('CustomFieldDto.toDomainCustomField')] -> [RETURNS] -> [DataClass('CustomField')] -/** - * @summary Преобразует [CustomFieldDto] (DTO API) в [CustomField] (доменную модель). - */ -fun CustomFieldDto.toDomainCustomField(): CustomField { - return CustomField( - name = this.name, - value = this.value +// [ENTITY: Function('Label.toEntity')] +// [RELATION: Function('Label.toEntity')] -> [RETURNS] -> [DataClass('LabelEntity')] +fun Label.toEntity(): LabelEntity { + return LabelEntity( + id = this.id, + name = this.name ) } -// [END_ENTITY: Function('CustomFieldDto.toDomainCustomField')] \ No newline at end of file +// [END_ENTITY: Function('Label.toEntity')] +// [END_FILE_Mapper.kt] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/di/DatabaseModule.kt b/data/src/main/java/com/homebox/lens/data/di/DatabaseModule.kt index 2283739..9632575 100644 --- a/data/src/main/java/com/homebox/lens/data/di/DatabaseModule.kt +++ b/data/src/main/java/com/homebox/lens/data/di/DatabaseModule.kt @@ -34,7 +34,7 @@ object DatabaseModule { context, HomeboxDatabase::class.java, HomeboxDatabase.DATABASE_NAME - ).build() + ).fallbackToDestructiveMigration().build() } // [END_ENTITY: Function('provideHomeboxDatabase')] diff --git a/data/src/main/java/com/homebox/lens/data/mapper/DomainToDto.kt b/data/src/main/java/com/homebox/lens/data/mapper/DomainToDto.kt new file mode 100644 index 0000000..fe25a5b --- /dev/null +++ b/data/src/main/java/com/homebox/lens/data/mapper/DomainToDto.kt @@ -0,0 +1,130 @@ +// [PACKAGE] com.homebox.lens.data.mapper +// [FILE] DomainToDto.kt +// [SEMANTICS] data, mapper, domain, dto +package com.homebox.lens.data.mapper + +// [IMPORTS] +import com.homebox.lens.data.api.dto.ItemCreateDto +import com.homebox.lens.data.api.dto.ItemUpdateDto +import com.homebox.lens.data.api.dto.LabelCreateDto +import com.homebox.lens.data.api.dto.LabelUpdateDto +import com.homebox.lens.data.api.dto.LocationCreateDto +import com.homebox.lens.data.api.dto.LocationUpdateDto +import com.homebox.lens.domain.model.ItemCreate as DomainItemCreate +import com.homebox.lens.domain.model.ItemUpdate as DomainItemUpdate +import com.homebox.lens.domain.model.LabelCreate as DomainLabelCreate +import com.homebox.lens.domain.model.LabelUpdate as DomainLabelUpdate +import com.homebox.lens.domain.model.LocationCreate as DomainLocationCreate +import com.homebox.lens.domain.model.LocationUpdate as DomainLocationUpdate +// [END_IMPORTS] + +// [ENTITY: Function('DomainItemCreate.toDto')] +// [RELATION: Function('DomainItemCreate.toDto')] -> [RETURNS] -> [DataClass('ItemCreateDto')] +fun DomainItemCreate.toDto(): ItemCreateDto { + return ItemCreateDto( + name = this.name, + description = this.description, + quantity = this.quantity, + archived = this.archived, + assetId = this.assetId, + insured = this.insured, + lifetimeWarranty = this.lifetimeWarranty, + manufacturer = this.manufacturer, + modelNumber = this.modelNumber, + notes = this.notes, + parentId = this.parentId, + purchaseFrom = this.purchaseFrom, + purchasePrice = this.purchasePrice?.toDouble(), + purchaseTime = this.purchaseTime, + serialNumber = this.serialNumber, + soldNotes = this.soldNotes, + soldPrice = this.soldPrice?.toDouble(), + soldTime = this.soldTime, + soldTo = this.soldTo, + syncChildItemsLocations = this.syncChildItemsLocations, + warrantyDetails = this.warrantyDetails, + warrantyExpires = this.warrantyExpires, + locationId = this.locationId, + labelIds = this.labelIds + ) +} +// [END_ENTITY: Function('ItemCreate.toDto')] + +// [ENTITY: Function('DomainItemUpdate.toDto')] +// [RELATION: Function('DomainItemUpdate.toDto')] -> [RETURNS] -> [DataClass('ItemUpdateDto')] +fun DomainItemUpdate.toDto(): ItemUpdateDto { + return ItemUpdateDto( + name = this.name, + description = this.description, + quantity = this.quantity, + archived = this.archived, + assetId = this.assetId, + insured = this.insured, + lifetimeWarranty = this.lifetimeWarranty, + manufacturer = this.manufacturer, + modelNumber = this.modelNumber, + notes = this.notes, + parentId = this.parentId, + purchaseFrom = this.purchaseFrom, + purchasePrice = this.purchasePrice?.toDouble(), + purchaseTime = this.purchaseTime, + serialNumber = this.serialNumber, + soldNotes = this.soldNotes, + soldPrice = this.soldPrice?.toDouble(), + soldTime = this.soldTime, + soldTo = this.soldTo, + syncChildItemsLocations = this.syncChildItemsLocations, + warrantyDetails = this.warrantyDetails, + warrantyExpires = this.warrantyExpires, + locationId = this.locationId, + labelIds = this.labelIds + ) +} +// [END_ENTITY: Function('ItemUpdate.toDto')] + +// [ENTITY: Function('DomainLabelCreate.toDto')] +// [RELATION: Function('DomainLabelCreate.toDto')] -> [RETURNS] -> [DataClass('LabelCreateDto')] +fun DomainLabelCreate.toDto(): LabelCreateDto { + return LabelCreateDto( + name = this.name, + color = this.color, + description = this.description + ) +} +// [END_ENTITY: Function('LabelCreate.toDto')] + +// [ENTITY: Function('DomainLabelUpdate.toDto')] +// [RELATION: Function('DomainLabelUpdate.toDto')] -> [RETURNS] -> [DataClass('LabelUpdateDto')] +fun DomainLabelUpdate.toDto(): LabelUpdateDto { + return LabelUpdateDto( + name = this.name, + color = this.color, + description = this.description + ) +} +// [END_ENTITY: Function('DomainLabelUpdate.toDto')] + +// [ENTITY: Function('DomainLocationCreate.toDto')] +// [RELATION: Function('DomainLocationCreate.toDto')] -> [RETURNS] -> [DataClass('LocationCreateDto')] +fun DomainLocationCreate.toDto(): LocationCreateDto { + return LocationCreateDto( + name = this.name, + parentId = this.parentId, + color = null, + description = this.description + ) +} +// [END_ENTITY: Function('DomainLocationCreate.toDto')] + +// [ENTITY: Function('DomainLocationUpdate.toDto')] +// [RELATION: Function('DomainLocationUpdate.toDto')] -> [RETURNS] -> [DataClass('LocationUpdateDto')] +fun DomainLocationUpdate.toDto(): LocationUpdateDto { + return LocationUpdateDto( + name = this.name, + color = this.color, + description = this.description + ) +} +// [END_ENTITY: Function('DomainLocationUpdate.toDto')] + +// [END_FILE_DomainToDto.kt] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/mapper/DtoToDomain.kt b/data/src/main/java/com/homebox/lens/data/mapper/DtoToDomain.kt new file mode 100644 index 0000000..4c1f86e --- /dev/null +++ b/data/src/main/java/com/homebox/lens/data/mapper/DtoToDomain.kt @@ -0,0 +1,260 @@ +// [PACKAGE] com.homebox.lens.data.mapper +// [FILE] DtoToDomain.kt +// [SEMANTICS] data, mapper, dto, domain +package com.homebox.lens.data.mapper + +// [IMPORTS] +import com.homebox.lens.data.api.dto.* +import com.homebox.lens.domain.model.CustomField as DomainCustomField +import com.homebox.lens.domain.model.GroupStatistics as DomainGroupStatistics +import com.homebox.lens.domain.model.Image as DomainImage +import com.homebox.lens.domain.model.Item as DomainItem +import com.homebox.lens.domain.model.ItemAttachment as DomainItemAttachment +import com.homebox.lens.domain.model.ItemOut as DomainItemOut +import com.homebox.lens.domain.model.ItemSummary as DomainItemSummary +import com.homebox.lens.domain.model.Label as DomainLabel +import com.homebox.lens.domain.model.LabelOut as DomainLabelOut +import com.homebox.lens.domain.model.LabelSummary as DomainLabelSummary +import com.homebox.lens.domain.model.Location as DomainLocation +import com.homebox.lens.domain.model.LocationOut as DomainLocationOut +import com.homebox.lens.domain.model.LocationOutCount as DomainLocationOutCount +import com.homebox.lens.domain.model.MaintenanceEntry as DomainMaintenanceEntry +import com.homebox.lens.domain.model.PaginationResult as DomainPaginationResult +// [END_IMPORTS] + +// [ENTITY: Function('ItemOutDto.toDomain')] +// [RELATION: Function('ItemOutDto.toDomain')] -> [RETURNS] -> [DataClass('DomainItemOut')] +fun ItemOutDto.toDomain(): DomainItemOut { + return DomainItemOut( + id = this.id, + name = this.name, + assetId = this.assetId, + description = this.description, + notes = this.notes, + serialNumber = this.serialNumber, + quantity = this.quantity, + isArchived = this.isArchived, + purchasePrice = this.purchasePrice, + purchaseTime = this.purchaseTime, + purchaseFrom = this.purchaseFrom, + warrantyExpires = this.warrantyExpires, + warrantyDetails = this.warrantyDetails, + lifetimeWarranty = this.lifetimeWarranty, + insured = this.insured, + manufacturer = this.manufacturer, + modelNumber = this.modelNumber, + soldPrice = this.soldPrice, + soldTime = this.soldTime, + soldTo = this.soldTo, + soldNotes = this.soldNotes, + syncChildItemsLocations = this.syncChildItemsLocations, + location = this.location?.toDomain(), + parent = this.parent?.toDomain(), + children = this.children.map { it.toDomain() }, + labels = this.labels.map { it.toDomain() }, + attachments = this.attachments.map { it.toDomain() }, + images = this.images.map { it.toDomain() }, + fields = this.fields.map { it.toDomain() }, + maintenance = this.maintenance.map { it.toDomain() }, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} + +fun ItemOutDto.toDomainItem(): DomainItem { + return DomainItem( + id = this.id, + name = this.name, + description = this.description, + quantity = this.quantity, + image = this.images.firstOrNull { it.isPrimary }?.path, + location = this.location?.toDomainLocation(), + labels = this.labels.map { it.toDomainLabel() }, + purchasePrice = this.purchasePrice, + createdAt = this.createdAt, + archived = this.isArchived, + assetId = this.assetId, + fields = this.fields.map { it.toDomain() }, + insured = this.insured ?: false, + lifetimeWarranty = this.lifetimeWarranty ?: false, + manufacturer = this.manufacturer, + modelNumber = this.modelNumber, + notes = this.notes, + parentId = this.parent?.id, + purchaseFrom = this.purchaseFrom, + purchaseTime = this.purchaseTime, + serialNumber = this.serialNumber, + soldNotes = this.soldNotes, + soldPrice = this.soldPrice, + soldTime = this.soldTime, + soldTo = this.soldTo, + syncChildItemsLocations = this.syncChildItemsLocations ?: false, + warrantyDetails = this.warrantyDetails, + warrantyExpires = this.warrantyExpires + ) +} +// [END_ENTITY: Function('ItemOutDto.toDomain')] + +// [ENTITY: Function('ItemSummaryDto.toDomain')] +// [RELATION: Function('ItemSummaryDto.toDomain')] -> [RETURNS] -> [DataClass('DomainItemSummary')] +fun ItemSummaryDto.toDomain(): DomainItemSummary { + return DomainItemSummary( + id = this.id, + name = this.name, + assetId = this.assetId, + image = this.image?.toDomain(), + isArchived = this.isArchived, + labels = this.labels.map { it.toDomain() }, + location = this.location?.toDomain(), + value = this.value, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} +// [END_ENTITY: Function('ItemSummaryDto.toDomain')] + +// [ENTITY: Function('LabelOutDto.toDomain')] +// [RELATION: Function('LabelOutDto.toDomain')] -> [RETURNS] -> [DataClass('DomainLabelOut')] +fun LabelOutDto.toDomain(): DomainLabelOut { + return DomainLabelOut( + id = this.id, + name = this.name, + color = this.color ?: "", + isArchived = this.isArchived ?: false, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} + +fun LabelOutDto.toDomainLabel(): DomainLabel { + return DomainLabel( + id = this.id, + name = this.name + ) +} +// [END_ENTITY: Function('LabelOutDto.toDomain')] + +// [ENTITY: Function('LocationOutDto.toDomain')] +// [RELATION: Function('LocationOutDto.toDomain')] -> [RETURNS] -> [DataClass('DomainLocationOut')] +fun LocationOutDto.toDomain(): DomainLocationOut { + return DomainLocationOut( + id = this.id, + name = this.name, + color = this.color, + isArchived = this.isArchived, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} + +fun LocationOutDto.toDomainLocation(): DomainLocation { + return DomainLocation( + id = this.id, + name = this.name + ) +} +// [END_ENTITY: Function('LocationOutDto.toDomain')] + +// [ENTITY: Function('LocationOutCountDto.toDomain')] +// [RELATION: Function('LocationOutCountDto.toDomain')] -> [RETURNS] -> [DataClass('DomainLocationOutCount')] +fun LocationOutCountDto.toDomain(): DomainLocationOutCount { + return DomainLocationOutCount( + id = this.id, + name = this.name, + color = this.color ?: "", + isArchived = this.isArchived ?: false, + itemCount = this.itemCount, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} +// [END_ENTITY: Function('LocationOutCountDto.toDomain')] + +// [ENTITY: Function('PaginationResultDto.toDomain')] +// [RELATION: Function('PaginationResultDto.toDomain')] -> [RETURNS] -> [DataClass('DomainPaginationResult')] +fun PaginationResultDto.toDomain(transform: (T) -> R): DomainPaginationResult { + return DomainPaginationResult( + items = this.items.map(transform), + page = this.page, + pageSize = this.pageSize, + total = this.total + ) +} +// [END_ENTITY: Function('PaginationResultDto.toDomain')] + +// [ENTITY: Function('ImageDto.toDomain')] +// [RELATION: Function('ImageDto.toDomain')] -> [RETURNS] -> [DataClass('DomainImage')] +fun ImageDto.toDomain(): DomainImage { + return DomainImage( + id = this.id, + path = this.path, + isPrimary = this.isPrimary + ) +} +// [END_ENTITY: Function('ImageDto.toDomain')] + +// [ENTITY: Function('CustomFieldDto.toDomain')] +// [RELATION: Function('CustomFieldDto.toDomain')] -> [RETURNS] -> [DataClass('DomainCustomField')] +fun CustomFieldDto.toDomain(): DomainCustomField { + return DomainCustomField( + name = this.name, + value = this.value, + type = this.type + ) +} +// [END_ENTITY: Function('CustomFieldDto.toDomain')] + +// [ENTITY: Function('ItemAttachmentDto.toDomain')] +// [RELATION: Function('ItemAttachmentDto.toDomain')] -> [RETURNS] -> [DataClass('DomainItemAttachment')] +fun ItemAttachmentDto.toDomain(): DomainItemAttachment { + return DomainItemAttachment( + id = this.id, + name = this.name, + path = this.path, + type = this.type, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} +// [END_ENTITY: Function('ItemAttachmentDto.toDomain')] + +// [ENTITY: Function('MaintenanceEntryDto.toDomain')] +// [RELATION: Function('MaintenanceEntryDto.toDomain')] -> [RETURNS] -> [DataClass('DomainMaintenanceEntry')] +fun MaintenanceEntryDto.toDomain(): DomainMaintenanceEntry { + return DomainMaintenanceEntry( + id = this.id, + itemId = this.itemId, + title = this.title, + details = this.details, + dueAt = this.dueAt, + completedAt = this.completedAt, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} +// [END_ENTITY: Function('MaintenanceEntryDto.toDomain')] + +// [ENTITY: Function('GroupStatisticsDto.toDomain')] +// [RELATION: Function('GroupStatisticsDto.toDomain')] -> [RETURNS] -> [DataClass('DomainGroupStatistics')] +fun GroupStatisticsDto.toDomain(): DomainGroupStatistics { + return DomainGroupStatistics( + items = this.totalItems, + labels = this.totalLabels, + locations = this.totalLocations, + totalValue = this.totalItemPrice + ) +} +// [END_ENTITY: Function('GroupStatisticsDto.toDomain')] + +// [ENTITY: Function('LabelSummaryDto.toDomain')] +// [RELATION: Function('LabelSummaryDto.toDomain')] -> [RETURNS] -> [DataClass('DomainLabelSummary')] +fun LabelSummaryDto.toDomain(): DomainLabelSummary { + return DomainLabelSummary( + id = this.id, + name = this.name, + color = this.color ?: "" + ) +} +// [END_ENTITY: Function('LabelSummaryDto.toDomain')] + +// [END_FILE_DtoToDomain.kt] \ No newline at end of file diff --git a/data/src/main/java/com/homebox/lens/data/repository/ItemRepositoryImpl.kt b/data/src/main/java/com/homebox/lens/data/repository/ItemRepositoryImpl.kt index 2ec8f09..a9efbdd 100644 --- a/data/src/main/java/com/homebox/lens/data/repository/ItemRepositoryImpl.kt +++ b/data/src/main/java/com/homebox/lens/data/repository/ItemRepositoryImpl.kt @@ -5,15 +5,10 @@ package com.homebox.lens.data.repository // [IMPORTS] import com.homebox.lens.data.api.HomeboxApiService -import com.homebox.lens.data.api.dto.LabelCreateDto -import com.homebox.lens.data.api.dto.toDomain -import com.homebox.lens.data.api.dto.toDto -import com.homebox.lens.data.api.dto.LocationCreateDto -import com.homebox.lens.data.api.dto.LocationUpdateDto -import com.homebox.lens.data.api.dto.LabelUpdateDto -import com.homebox.lens.data.api.dto.LocationOutDto import com.homebox.lens.data.db.dao.ItemDao -import com.homebox.lens.data.db.entity.toDomain +import com.homebox.lens.data.db.entity.toDomainItemSummary +import com.homebox.lens.data.mapper.toDomain +import com.homebox.lens.data.mapper.toDto import com.homebox.lens.domain.model.* import com.homebox.lens.domain.repository.ItemRepository import kotlinx.coroutines.flow.Flow @@ -151,43 +146,11 @@ class ItemRepositoryImpl @Inject constructor( // [RELATION: Function('getRecentlyAddedItems')] -> [RETURNS] -> [DataStructure('Flow>')] override fun getRecentlyAddedItems(limit: Int): Flow> { return itemDao.getRecentlyAddedItems(limit).map { entities -> - entities.map { it.toDomain() } + entities.map { it.toDomainItemSummary() } } } // [END_ENTITY: Function('getRecentlyAddedItems')] } // [END_ENTITY: Repository('ItemRepositoryImpl')] -// [ENTITY: Function('toDto')] -// [RELATION: Function('toDto')] -> [RETURNS] -> [DataClass('LabelCreateDto')] -private fun LabelCreate.toDto(): LabelCreateDto { - return LabelCreateDto( - name = this.name, - color = this.color, - description = null // Description is not part of the domain model for creation. - ) -} -// [END_ENTITY: Function('toDto')] - -// [ENTITY: Function('toDto')] -// [RELATION: Function('toDto')] -> [RETURNS] -> [DataClass('LocationCreateDto')] -private fun LocationCreate.toDto(): LocationCreateDto { - return LocationCreateDto( - name = this.name, - color = this.color, - description = null // Description is not part of the domain model for creation. - ) -} -// [END_ENTITY: Function('toDto')] - -// [ENTITY: Function('toDto')] -// [RELATION: Function('toDto')] -> [RETURNS] -> [DataClass('LabelUpdateDto')] -private fun LabelUpdate.toDto(): LabelUpdateDto { - return LabelUpdateDto( - name = this.name, - color = this.color - ) -} -// [END_ENTITY: Function('toDto')] - // [END_FILE_ItemRepositoryImpl.kt] \ No newline at end of file diff --git a/domain/src/main/java/com/homebox/lens/domain/model/Item.kt b/domain/src/main/java/com/homebox/lens/domain/model/Item.kt index 1c150f4..b0ee0b5 100644 --- a/domain/src/main/java/com/homebox/lens/domain/model/Item.kt +++ b/domain/src/main/java/com/homebox/lens/domain/model/Item.kt @@ -50,7 +50,7 @@ data class Item( val image: String?, val location: Location?, val labels: List