From 556b7f7c7dcbbce5cc6e1815c9c8db8894cc225f Mon Sep 17 00:00:00 2001 From: busya Date: Sat, 4 Oct 2025 09:53:10 +0300 Subject: [PATCH] feat(enrichment): apply semantic markup --- .../roles/semantic_enrichment_agent.xml | 105 +++++++++++ agent_promts/roles/semantic_linter.xml | 18 +- agent_promts/shared/metrics_catalog.xml | 8 + .../java/com/homebox/lens/MainActivity.kt | 4 +- .../java/com/homebox/lens/MainApplication.kt | 4 +- .../com/homebox/lens/navigation/NavGraph.kt | 10 +- .../lens/navigation/NavigationActions.kt | 12 +- .../com/homebox/lens/navigation/Screen.kt | 46 ++--- .../com/homebox/lens/ui/common/AppDrawer.kt | 10 +- .../homebox/lens/ui/common/MainScaffold.kt | 18 +- .../homebox/lens/ui/components/ColorPicker.kt | 10 +- .../lens/ui/components/LoadingOverlay.kt | 4 +- .../com/homebox/lens/ui/mapper/ItemMapper.kt | 2 +- .../ui/screen/dashboard/DashboardScreen.kt | 52 +++--- .../ui/screen/dashboard/DashboardUiState.kt | 22 +-- .../ui/screen/dashboard/DashboardViewModel.kt | 18 +- .../inventorylist/InventoryListScreen.kt | 8 +- .../inventorylist/InventoryListViewModel.kt | 2 +- .../screen/itemdetails/ItemDetailsScreen.kt | 8 +- .../itemdetails/ItemDetailsViewModel.kt | 2 +- .../lens/ui/screen/itemedit/ItemEditScreen.kt | 165 ++++++++++++++---- .../ui/screen/itemedit/ItemEditViewModel.kt | 7 +- .../ui/screen/labeledit/LabelEditScreen.kt | 10 +- .../ui/screen/labeledit/LabelEditViewModel.kt | 2 +- .../ui/screen/labelslist/LabelsListScreen.kt | 24 +-- .../ui/screen/labelslist/LabelsListUiState.kt | 24 +-- .../screen/labelslist/LabelsListViewModel.kt | 40 ++--- .../screen/locationedit/LocationEditScreen.kt | 6 +- .../locationslist/LocationsListScreen.kt | 36 ++-- .../locationslist/LocationsListUiState.kt | 14 +- .../locationslist/LocationsListViewModel.kt | 14 +- .../lens/ui/screen/search/SearchScreen.kt | 8 +- .../lens/ui/screen/search/SearchViewModel.kt | 2 +- .../lens/ui/screen/settings/SettingsScreen.kt | 8 +- .../lens/ui/screen/setup/SetupScreen.kt | 52 +++--- .../lens/ui/screen/splash/SplashScreen.kt | 54 +++--- .../java/com/homebox/lens/ui/theme/Color.kt | 2 +- .../java/com/homebox/lens/ui/theme/Theme.kt | 2 +- .../com/homebox/lens/ui/theme/Typography.kt | 2 +- app/src/main/res/values/strings.xml | 1 + .../lens/data/api/HomeboxApiService.kt | 2 +- .../lens/data/api/dto/CustomFieldDto.kt | 6 +- .../lens/data/api/dto/GroupStatisticsDto.kt | 6 +- .../com/homebox/lens/data/api/dto/ImageDto.kt | 12 +- .../lens/data/api/dto/ItemAttachmentDto.kt | 6 +- .../lens/data/api/dto/ItemCreateDto.kt | 6 +- .../com/homebox/lens/data/api/dto/ItemDto.kt | 74 -------- .../homebox/lens/data/api/dto/ItemOutDto.kt | 45 ++++- .../lens/data/api/dto/ItemSummaryDto.kt | 23 ++- .../lens/data/api/dto/ItemUpdateDto.kt | 2 +- .../lens/data/api/dto/LabelCreateDto.kt | 2 +- .../homebox/lens/data/api/dto/LabelOutDto.kt | 19 +- .../lens/data/api/dto/LabelSummaryDto.kt | 2 +- .../lens/data/api/dto/LabelUpdateDto.kt | 6 +- .../lens/data/api/dto/LocationCreateDto.kt | 5 +- .../homebox/lens/data/api/dto/LocationDto.kt | 34 ---- .../lens/data/api/dto/LocationOutCountDto.kt | 21 ++- .../lens/data/api/dto/LocationOutDto.kt | 18 +- .../lens/data/api/dto/LocationUpdateDto.kt | 6 +- .../homebox/lens/data/api/dto/LoginFormDto.kt | 5 +- .../lens/data/api/dto/MaintenanceEntryDto.kt | 6 +- .../lens/data/api/dto/PaginationDto.kt | 25 --- .../lens/data/api/dto/PaginationResultDto.kt | 17 +- .../lens/data/api/dto/StatisticsDto.kt | 25 --- .../lens/data/api/dto/TokenResponseDto.kt | 18 +- .../lens/data/api/mapper/TokenMapper.kt | 30 ---- .../lens/data/api/model/LoginRequest.kt | 24 +-- .../com/homebox/lens/data/db/Converters.kt | 2 +- .../homebox/lens/data/db/HomeboxDatabase.kt | 2 +- .../com/homebox/lens/data/db/dao/ItemDao.kt | 2 +- .../com/homebox/lens/data/db/dao/LabelDao.kt | 2 +- .../homebox/lens/data/db/dao/LocationDao.kt | 2 +- .../homebox/lens/data/db/entity/ItemEntity.kt | 2 +- .../lens/data/db/entity/ItemLabelCrossRef.kt | 2 +- .../lens/data/db/entity/ItemWithLabels.kt | 2 +- .../lens/data/db/entity/LabelEntity.kt | 2 +- .../lens/data/db/entity/LocationEntity.kt | 2 +- .../com/homebox/lens/data/db/entity/Mapper.kt | 6 +- .../com/homebox/lens/data/di/ApiModule.kt | 6 +- .../homebox/lens/data/di/DatabaseModule.kt | 4 +- .../homebox/lens/data/di/RepositoryModule.kt | 12 +- .../com/homebox/lens/data/di/StorageModule.kt | 2 +- .../homebox/lens/data/mapper/DomainToDto.kt | 2 +- .../homebox/lens/data/mapper/DtoToDomain.kt | 9 +- .../data/repository/AuthRepositoryImpl.kt | 18 +- .../repository/CredentialsRepositoryImpl.kt | 32 ++-- .../data/repository/ItemRepositoryImpl.kt | 2 +- .../lens/data/security/CryptoManager.kt | 2 +- .../homebox/lens/domain/model/CustomField.kt | 2 +- .../lens/domain/model/GroupStatistics.kt | 2 +- .../com/homebox/lens/domain/model/Image.kt | 2 +- .../com/homebox/lens/domain/model/Item.kt | 63 ++++--- .../lens/domain/model/ItemAttachment.kt | 2 +- .../homebox/lens/domain/model/ItemCreate.kt | 44 +++-- .../com/homebox/lens/domain/model/ItemOut.kt | 77 ++++---- .../homebox/lens/domain/model/ItemSummary.kt | 29 +-- .../homebox/lens/domain/model/ItemUpdate.kt | 46 +++-- .../com/homebox/lens/domain/model/Label.kt | 10 +- .../homebox/lens/domain/model/LabelCreate.kt | 11 +- .../com/homebox/lens/domain/model/LabelOut.kt | 19 +- .../homebox/lens/domain/model/LabelSummary.kt | 11 +- .../homebox/lens/domain/model/LabelUpdate.kt | 9 +- .../com/homebox/lens/domain/model/Location.kt | 10 +- .../lens/domain/model/LocationCreate.kt | 12 +- .../homebox/lens/domain/model/LocationOut.kt | 18 +- .../lens/domain/model/LocationOutCount.kt | 21 ++- .../lens/domain/model/LocationUpdate.kt | 9 +- .../lens/domain/model/MaintenanceEntry.kt | 23 +-- .../lens/domain/model/PaginationResult.kt | 17 +- .../homebox/lens/domain/model/Statistics.kt | 15 +- .../lens/domain/model/TokenResponse.kt | 8 +- .../lens/domain/repository/AuthRepository.kt | 22 +-- .../lens/domain/repository/ItemRepository.kt | 2 +- .../lens/domain/usecase/CreateItemUseCase.kt | 14 +- .../lens/domain/usecase/CreateLabelUseCase.kt | 16 +- .../domain/usecase/CreateLocationUseCase.kt | 16 +- .../lens/domain/usecase/DeleteItemUseCase.kt | 12 +- .../lens/domain/usecase/DeleteLabelUseCase.kt | 12 +- .../domain/usecase/DeleteLocationUseCase.kt | 12 +- .../domain/usecase/GetAllLabelsUseCase.kt | 12 +- .../domain/usecase/GetAllLocationsUseCase.kt | 12 +- .../domain/usecase/GetItemDetailsUseCase.kt | 14 +- .../domain/usecase/GetLabelDetailsUseCase.kt | 16 +- .../usecase/GetRecentlyAddedItemsUseCase.kt | 20 +-- .../domain/usecase/GetStatisticsUseCase.kt | 12 +- .../lens/domain/usecase/LoginUseCase.kt | 18 +- .../lens/domain/usecase/SearchItemsUseCase.kt | 12 +- .../domain/usecase/SyncInventoryUseCase.kt | 16 +- .../lens/domain/usecase/UpdateItemUseCase.kt | 14 +- .../lens/domain/usecase/UpdateLabelUseCase.kt | 16 +- .../domain/usecase/UpdateLocationUseCase.kt | 16 +- tasks/enrichment_task_1.xml | 17 ++ tasks/enrichment_ui.xml | 6 + 133 files changed, 1220 insertions(+), 943 deletions(-) create mode 100644 agent_promts/roles/semantic_enrichment_agent.xml delete mode 100644 data/src/main/java/com/homebox/lens/data/api/dto/ItemDto.kt delete mode 100644 data/src/main/java/com/homebox/lens/data/api/dto/LocationDto.kt delete mode 100644 data/src/main/java/com/homebox/lens/data/api/dto/PaginationDto.kt delete mode 100644 data/src/main/java/com/homebox/lens/data/api/dto/StatisticsDto.kt delete mode 100644 data/src/main/java/com/homebox/lens/data/api/mapper/TokenMapper.kt create mode 100644 tasks/enrichment_task_1.xml create mode 100644 tasks/enrichment_ui.xml diff --git a/agent_promts/roles/semantic_enrichment_agent.xml b/agent_promts/roles/semantic_enrichment_agent.xml new file mode 100644 index 0000000..6591bf0 --- /dev/null +++ b/agent_promts/roles/semantic_enrichment_agent.xml @@ -0,0 +1,105 @@ + + + + + Этот документ определяет операционный протокол для **исполнения роли 'Агента Семантического Обогащения'**. Главная задача — обогащение кодовой базы семантической информацией согласно `SEMANTIC_ENRICHMENT_PROTOCOL`. + 1.0 + + + + + + + + - ..agent_promts/interfaces/task_channel_interface.xml + - ..agent_promts/protocols/semantic_enrichment_protocol.xml + + + + + При исполнении этой роли, я действую как агент семантического обогащения. Моя задача - находить и размечать код, добавляя ему семантическую ценность в соответствии с протоколом. + Проактивно обогащать кодовую базу семантической разметкой для улучшения машиночитаемости и анализа. + + + + + Моя работа заключается в добавлении семантических комментариев и аннотаций, не изменяя логику существующего кода. + + + Все изменения должны быть доступны для просмотра, например, через Pull Request. + + + + + Загрузить и полностью проанализировать `agent_promts/protocols/semantic_enrichment_protocol.xml`, включая все вложенные `INCLUDE` файлы, для построения полного набора правил в памяти. + + + + Задачи для этой роли определяют, какие части кодовой базы нужно обогатить. + + + full_project | directory | file_list + + + + + + ]]> + + + + + + + + + + CALL MyTaskChannel.UpdateTaskStatus(IssueID={WorkOrder.ID}, NewStatus='status::in-progress') + + + + Извлечь `` из `WorkOrder`. + feature/{WorkOrder.ID}/semantic-enrichment + CALL MyTaskChannel.CreateBranch(BranchName={BranchName}) + Определить `files_to_process` на основе `SCOPE` и `TARGET`. + Для каждого файла в `files_to_process` применить правила из `SEMANTIC_ENRICHMENT_PROTOCOL`. + + + + + Сделать коммит с сообщением: `feat(enrichment): apply semantic markup`. + CALL MyTaskChannel.CommitChanges(...) + + CALL MyTaskChannel.AddComment(IssueID={WorkOrder.ID}, CommentBody='Enrichment complete. PR #{PrID} is ready for review.') + + + CALL MyTaskChannel.AddComment(IssueID={WorkOrder.ID}, CommentBody='Enrichment complete. No new semantic markup was added.') + + + + + CALL MyTaskChannel.UpdateTaskStatus(IssueID={WorkOrder.ID}, NewStatus='status::completed') + + + + Отправить метрики через `MyMetricsSink`. + + + + + + +`WorkOrder {WorkOrder.ID} completed. + - Files Processed: {EnrichmentMetrics.files_processed} + - Entities Enriched: {EnrichmentMetrics.entities_enriched} + - Relations Added: {EnrichmentMetrics.relations_added} + - Contracts Added: {EnrichmentMetrics.contracts_added} + - Logs Added: {EnrichmentMetrics.logs_added}` + + CALL MyLogSink.Log(FileName="logs/enrichment_agent_log.txt", Content={LogMessage}) + + + +]]> \ No newline at end of file diff --git a/agent_promts/roles/semantic_linter.xml b/agent_promts/roles/semantic_linter.xml index b3565f0..110f287 100644 --- a/agent_promts/roles/semantic_linter.xml +++ b/agent_promts/roles/semantic_linter.xml @@ -11,13 +11,13 @@ - - ../interfaces/task_channel_interface.xml - - ../protocols/semantic_enrichment_protocol.xml + - ..agent_promts/interfaces/task_channel_interface.xml + - ..agent_promts/protocols/semantic_enrichment_protocol.xml - При исполнении этой роли, я, Gemini, действую как автоматизированный хранитель чистоты кода. Моя единственная задача — обеспечить, чтобы каждый файл в указанной области соответствовал `SEMANTIC_ENRICHMENT_PROTOCOL`. + При исполнении этой роли, я, действую как автоматизированный хранитель чистоты кода. Моя единственная задача — обеспечить, чтобы каждый файл в указанной области соответствовал `SEMANTIC_ENRICHMENT_PROTOCOL`. Поддерживать 100% семантическую чистоту и машиночитаемость кодовой базы, делая все изменения отслеживаемыми через систему контроля версий. @@ -30,18 +30,6 @@ - - - - - - - find . -name "*.kt" - git diff --name-only {commit_range} - - - - Задачи для этой роли должны содержать XML-блок, определяющий режим работы. diff --git a/agent_promts/shared/metrics_catalog.xml b/agent_promts/shared/metrics_catalog.xml index 8999952..9e33dd2 100644 --- a/agent_promts/shared/metrics_catalog.xml +++ b/agent_promts/shared/metrics_catalog.xml @@ -44,4 +44,12 @@ + + Количество обработанных файлов. + Количество обогащенных сущностей (добавлены якоря ENTITY). + Количество добавленных семантических связей (якоря RELATION). + Количество добавленных KDoc-контрактов. + Количество добавленных структурированных логов. + + diff --git a/app/src/main/java/com/homebox/lens/MainActivity.kt b/app/src/main/java/com/homebox/lens/MainActivity.kt index 0752d4c..e3519f7 100644 --- a/app/src/main/java/com/homebox/lens/MainActivity.kt +++ b/app/src/main/java/com/homebox/lens/MainActivity.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens // [FILE] MainActivity.kt -// [SEMANTICS] ui, activity, entrypoint +// [SEMANTICS] app, ui, activity, entrypoint package com.homebox.lens // [IMPORTS] @@ -22,7 +22,7 @@ import timber.log.Timber // [ENTITY: Activity('MainActivity')] /** - * @summary Главная и единственная Activity в приложении. + * @summary The main and only Activity in the application. */ @AndroidEntryPoint class MainActivity : ComponentActivity() { diff --git a/app/src/main/java/com/homebox/lens/MainApplication.kt b/app/src/main/java/com/homebox/lens/MainApplication.kt index bdb7afb..57c6b21 100644 --- a/app/src/main/java/com/homebox/lens/MainApplication.kt +++ b/app/src/main/java/com/homebox/lens/MainApplication.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens // [FILE] MainApplication.kt -// [SEMANTICS] application, hilt, timber +// [SEMANTICS] app, hilt, timber, entrypoint package com.homebox.lens // [IMPORTS] @@ -11,7 +11,7 @@ import timber.log.Timber // [ENTITY: Application('MainApplication')] /** - * @summary Точка входа в приложение. Инициализирует Hilt и Timber. + * @summary The entry point of the application. Initializes Hilt and Timber. */ @HiltAndroidApp class MainApplication : Application() { diff --git a/app/src/main/java/com/homebox/lens/navigation/NavGraph.kt b/app/src/main/java/com/homebox/lens/navigation/NavGraph.kt index 8d05b1d..512b732 100644 --- a/app/src/main/java/com/homebox/lens/navigation/NavGraph.kt +++ b/app/src/main/java/com/homebox/lens/navigation/NavGraph.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.navigation // [FILE] NavGraph.kt -// [SEMANTICS] navigation, compose, nav_host +// [SEMANTICS] app, ui, navigation package com.homebox.lens.navigation @@ -34,11 +34,11 @@ import com.homebox.lens.ui.screen.splash.SplashScreen // [RELATION: Function('NavGraph')] -> [CREATES_INSTANCE_OF] -> [Class('NavigationActions')] // [RELATION: Function('NavGraph')] -> [USES] -> [Screen('SplashScreen')] /** - * @summary Определяет граф навигации для всего приложения с использованием Jetpack Compose Navigation. - * @param navController Контроллер навигации. + * @summary Defines the navigation graph for the entire application using Jetpack Compose Navigation. + * @param navController The navigation controller. * @see Screen - * @sideeffect Регистрирует все экраны и управляет состоянием навигации. - * @invariant Стартовый экран - `Screen.Setup`. + * @sideeffect Registers all screens and manages the navigation state. + * @invariant The start screen is `Screen.Splash`. */ @Composable fun NavGraph( diff --git a/app/src/main/java/com/homebox/lens/navigation/NavigationActions.kt b/app/src/main/java/com/homebox/lens/navigation/NavigationActions.kt index ff0ee98..566f74e 100644 --- a/app/src/main/java/com/homebox/lens/navigation/NavigationActions.kt +++ b/app/src/main/java/com/homebox/lens/navigation/NavigationActions.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.navigation // [FILE] NavigationActions.kt -// [SEMANTICS] navigation, controller, actions +// [SEMANTICS] app, ui, navigation, actions package com.homebox.lens.navigation // [IMPORTS] @@ -11,16 +11,16 @@ import timber.log.Timber // [ENTITY: Class('NavigationActions')] // [RELATION: Class('NavigationActions')] -> [DEPENDS_ON] -> [Framework('NavHostController')] /** - * @summary Класс-обертка над NavHostController для предоставления типизированных навигационных действий. - * @param navController Контроллер Jetpack Navigation. - * @invariant Все навигационные действия должны использовать предоставленный navController. + * @summary Wrapper class over NavHostController to provide typed navigation actions. + * @param navController The Jetpack Navigation controller. + * @invariant All navigation actions must use the provided navController. */ class NavigationActions(private val navController: NavHostController) { // [ENTITY: Function('navigateToDashboard')] /** - * @summary Навигация на главный экран. - * @sideeffect Очищает back stack до главного экрана, чтобы избежать циклов. + * @summary Navigation to the main screen. + * @sideeffect Clears the back stack up to the main screen to avoid cycles. */ fun navigateToDashboard() { Timber.i("[INFO][ACTION][navigate_to_dashboard] Navigating to Dashboard.") diff --git a/app/src/main/java/com/homebox/lens/navigation/Screen.kt b/app/src/main/java/com/homebox/lens/navigation/Screen.kt index eb34239..98b5642 100644 --- a/app/src/main/java/com/homebox/lens/navigation/Screen.kt +++ b/app/src/main/java/com/homebox/lens/navigation/Screen.kt @@ -1,13 +1,13 @@ // [PACKAGE] com.homebox.lens.navigation // [FILE] Screen.kt -// [SEMANTICS] navigation, routes, sealed_class +// [SEMANTICS] app, ui, navigation, routes package com.homebox.lens.navigation // [ENTITY: SealedClass('Screen')] /** - * @summary Запечатанный класс для определения маршрутов навигации в приложении. - * @description Обеспечивает типобезопасность при навигации. - * @param route Строковый идентификатор маршрута. + * @summary Sealed class for defining navigation routes in the application. + * @description Provides type safety during navigation. + * @param route The string identifier of the route. */ sealed class Screen(val route: String) { // [ENTITY: Object('Splash')] @@ -26,11 +26,11 @@ sealed class Screen(val route: String) { data object InventoryList : Screen("inventory_list_screen") { // [ENTITY: Function('withFilter')] /** - * @summary Создает маршрут для экрана списка инвентаря с параметром фильтра. - * @param key Ключ фильтра (например, "label" или "location"). - * @param value Значение фильтра (например, ID метки или местоположения). - * @return Строку полного маршрута с query-параметром. - * @throws IllegalArgumentException если ключ или значение пустые. + * @summary Creates a route for the inventory list screen with a filter parameter. + * @param key The filter key (e.g., "label" or "location"). + * @param value The filter value (e.g., the ID of the label or location). + * @return A string of the full route with a query parameter. + * @throws IllegalArgumentException if the key or value is blank. */ fun withFilter(key: String, value: String): String { require(key.isNotBlank()) { "Filter key cannot be blank." } @@ -47,10 +47,10 @@ sealed class Screen(val route: String) { data object ItemDetails : Screen("item_details_screen/{itemId}") { // [ENTITY: Function('createRoute')] /** - * @summary Создает маршрут для экрана деталей элемента с указанным ID. - * @param itemId ID элемента для отображения. - * @return Строку полного маршрута. - * @throws IllegalArgumentException если itemId пустой. + * @summary Creates a route for the item details screen with the specified ID. + * @param itemId The ID of the item to display. + * @return A string of the full route. + * @throws IllegalArgumentException if itemId is blank. */ fun createRoute(itemId: String): String { require(itemId.isNotBlank()) { "itemId не может быть пустым." } @@ -66,9 +66,9 @@ sealed class Screen(val route: String) { data object ItemEdit : Screen("item_edit_screen?itemId={itemId}") { // [ENTITY: Function('createRoute')] /** - * @summary Создает маршрут для экрана редактирования элемента с указанным ID. - * @param itemId ID элемента для редактирования. Null, если создается новый элемент. - * @return Строку полного маршрута. + * @summary Creates a route for the item edit screen with the specified ID. + * @param itemId The ID of the item to edit. Null if a new item is being created. + * @return A string of the full route. */ fun createRoute(itemId: String? = null): String { return itemId?.let { "item_edit_screen?itemId=$it" } ?: "item_edit_screen" @@ -85,9 +85,9 @@ sealed class Screen(val route: String) { data object LabelEdit : Screen("label_edit_screen?labelId={labelId}") { // [ENTITY: Function('createRoute')] /** - * @summary Создает маршрут для экрана редактирования метки с указанным ID. - * @param labelId ID метки для редактирования. Null, если создается новая метка. - * @return Строку полного маршрута. + * @summary Creates a route for the label edit screen with the specified ID. + * @param labelId The ID of the label to edit. Null if a new label is being created. + * @return A string of the full route. */ fun createRoute(labelId: String? = null): String { return labelId?.let { "label_edit_screen?labelId=$it" } ?: "label_edit_screen" @@ -104,10 +104,10 @@ sealed class Screen(val route: String) { data object LocationEdit : Screen("location_edit_screen/{locationId}") { // [ENTITY: Function('createRoute')] /** - * @summary Создает маршрут для экрана редактирования местоположения с указанным ID. - * @param locationId ID местоположения для редактирования. - * @return Строку полного маршрута. - * @throws IllegalArgumentException если locationId пустой. + * @summary Creates a route for the location edit screen with the specified ID. + * @param locationId The ID of the location to edit. + * @return A string of the full route. + * @throws IllegalArgumentException if locationId is blank. */ fun createRoute(locationId: String): String { require(locationId.isNotBlank()) { "locationId не может быть пустым." } diff --git a/app/src/main/java/com/homebox/lens/ui/common/AppDrawer.kt b/app/src/main/java/com/homebox/lens/ui/common/AppDrawer.kt index 1cc14fe..0ab2b2d 100644 --- a/app/src/main/java/com/homebox/lens/ui/common/AppDrawer.kt +++ b/app/src/main/java/com/homebox/lens/ui/common/AppDrawer.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.common // [FILE] AppDrawer.kt -// [SEMANTICS] ui, common, navigation_drawer +// [SEMANTICS] app, ui, common, navigation package com.homebox.lens.ui.common // [IMPORTS] @@ -30,10 +30,10 @@ import com.homebox.lens.navigation.Screen // [ENTITY: Function('AppDrawerContent')] // [RELATION: Function('AppDrawerContent')] -> [DEPENDS_ON] -> [Class('NavigationActions')] /** - * @summary Контент для бокового навигационного меню (Drawer). - * @param currentRoute Текущий маршрут для подсветки активного элемента. - * @param navigationActions Объект с навигационными действиями. - * @param onCloseDrawer Лямбда для закрытия бокового меню. + * @summary Content for the side navigation menu (Drawer). + * @param currentRoute The current route to highlight the active item. + * @param navigationActions The object with navigation actions. + * @param onCloseDrawer Lambda to close the side menu. */ @Composable internal fun AppDrawerContent( diff --git a/app/src/main/java/com/homebox/lens/ui/common/MainScaffold.kt b/app/src/main/java/com/homebox/lens/ui/common/MainScaffold.kt index 0072a1f..6475455 100644 --- a/app/src/main/java/com/homebox/lens/ui/common/MainScaffold.kt +++ b/app/src/main/java/com/homebox/lens/ui/common/MainScaffold.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.common // [FILE] MainScaffold.kt -// [SEMANTICS] ui, common, scaffold, navigation_drawer +// [SEMANTICS] app, ui, common, scaffold package com.homebox.lens.ui.common @@ -21,14 +21,14 @@ import kotlinx.coroutines.launch // [RELATION: Function('MainScaffold')] -> [DEPENDS_ON] -> [Class('NavigationActions')] // [RELATION: Function('MainScaffold')] -> [CALLS] -> [Function('AppDrawerContent')] /** - * @summary Общая обертка для экранов, включающая Scaffold и Navigation Drawer. - * @param topBarTitle Заголовок для TopAppBar. - * @param currentRoute Текущий маршрут для подсветки активного элемента в Drawer. - * @param navigationActions Объект с навигационными действиями. - * @param topBarActions Composable-функция для отображения действий (иконок) в TopAppBar. - * @param content Основное содержимое экрана, которое будет отображено внутри Scaffold. - * @sideeffect Управляет состоянием (открыто/закрыто) бокового меню (ModalNavigationDrawer). - * @invariant TopAppBar всегда отображается с иконкой меню. + * @summary A common wrapper for screens that includes a Scaffold and Navigation Drawer. + * @param topBarTitle The title for the TopAppBar. + * @param currentRoute The current route to highlight the active item in the Drawer. + * @param navigationActions The object with navigation actions. + * @param topBarActions A Composable function to display actions (icons) in the TopAppBar. + * @param content The main content of the screen to be displayed inside the Scaffold. + * @sideeffect Manages the state (open/closed) of the side menu (ModalNavigationDrawer). + * @invariant The TopAppBar is always displayed with a menu icon. */ @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/java/com/homebox/lens/ui/components/ColorPicker.kt b/app/src/main/java/com/homebox/lens/ui/components/ColorPicker.kt index 3151ad5..1300707 100644 --- a/app/src/main/java/com/homebox/lens/ui/components/ColorPicker.kt +++ b/app/src/main/java/com/homebox/lens/ui/components/ColorPicker.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.components // [FILE] ColorPicker.kt -// [SEMANTICS] ui, component, color_selection +// [SEMANTICS] app, ui, component, color package com.homebox.lens.ui.components @@ -25,10 +25,10 @@ import com.homebox.lens.R // [ENTITY: Function('ColorPicker')] /** - * @summary Компонент для выбора цвета. - * @param selectedColor Текущий выбранный цвет в формате HEX строки (например, "#FFFFFF"). - * @param onColorSelected Лямбда-функция, вызываемая при выборе нового цвета. - * @param modifier Модификатор для настройки внешнего вида. + * @summary A component for color selection. + * @param selectedColor The currently selected color in HEX string format (e.g., "#FFFFFF"). + * @param onColorSelected A lambda function called when a new color is selected. + * @param modifier A modifier for customizing the appearance. */ @Composable fun ColorPicker( diff --git a/app/src/main/java/com/homebox/lens/ui/components/LoadingOverlay.kt b/app/src/main/java/com/homebox/lens/ui/components/LoadingOverlay.kt index 6c6ff3b..46e071c 100644 --- a/app/src/main/java/com/homebox/lens/ui/components/LoadingOverlay.kt +++ b/app/src/main/java/com/homebox/lens/ui/components/LoadingOverlay.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.components // [FILE] LoadingOverlay.kt -// [SEMANTICS] ui, component, loading +// [SEMANTICS] app, ui, component, loading package com.homebox.lens.ui.components @@ -18,7 +18,7 @@ import androidx.compose.ui.graphics.Color // [ENTITY: Function('LoadingOverlay')] /** - * @summary Полноэкранный оверлей с индикатором загрузки. + * @summary A full-screen overlay with a loading indicator. */ @Composable fun LoadingOverlay() { 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 index 01c0e98..6f7e262 100644 --- a/app/src/main/java/com/homebox/lens/ui/mapper/ItemMapper.kt +++ b/app/src/main/java/com/homebox/lens/ui/mapper/ItemMapper.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.mapper // [FILE] ItemMapper.kt -// [SEMANTICS] ui, mapper, item +// [SEMANTICS] app, ui, mapper, item package com.homebox.lens.ui.mapper import com.homebox.lens.domain.model.Item diff --git a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardScreen.kt index e2775c8..390a371 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardScreen.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.dashboard // [FILE] DashboardScreen.kt -// [SEMANTICS] ui, screen, dashboard, compose, navigation +// [SEMANTICS] app, ui, screen, dashboard package com.homebox.lens.ui.screen.dashboard // [IMPORTS] @@ -37,11 +37,11 @@ import timber.log.Timber // [RELATION: Function('DashboardScreen')] -> [DEPENDS_ON] -> [Class('NavigationActions')] // [RELATION: Function('DashboardScreen')] -> [CALLS] -> [Function('MainScaffold')] /** - * @summary Главная Composable-функция для экрана "Панель управления". - * @param viewModel ViewModel для этого экрана, предоставляется через Hilt. - * @param currentRoute Текущий маршрут для подсветки активного элемента в Drawer. - * @param navigationActions Объект с навигационными действиями. - * @sideeffect Вызывает навигационные лямбды при взаимодействии с UI. + * @summary The main Composable function for the "Dashboard" screen. + * @param viewModel The ViewModel for this screen, provided by Hilt. + * @param currentRoute The current route to highlight the active item in the Drawer. + * @param navigationActions The object with navigation actions. + * @sideeffect Calls navigation lambdas upon UI interaction. */ @Composable fun DashboardScreen( @@ -82,11 +82,11 @@ fun DashboardScreen( // [ENTITY: Function('DashboardContent')] // [RELATION: Function('DashboardContent')] -> [CONSUMES_STATE] -> [SealedInterface('DashboardUiState')] /** - * @summary Отображает основной контент экрана в зависимости от uiState. - * @param modifier Модификатор для стилизации. - * @param uiState Текущее состояние UI экрана. - * @param onLocationClick Лямбда-обработчик нажатия на местоположение. - * @param onLabelClick Лямбда-обработчик нажатия на метку. + * @summary Displays the main content of the screen depending on the uiState. + * @param modifier A modifier for styling. + * @param uiState The current UI state of the screen. + * @param onLocationClick A lambda handler for clicking on a location. + * @param onLabelClick A lambda handler for clicking on a label. */ @Composable private fun DashboardContent( @@ -132,8 +132,8 @@ private fun DashboardContent( // [ENTITY: Function('StatisticsSection')] // [RELATION: Function('StatisticsSection')] -> [DEPENDS_ON] -> [DataClass('GroupStatistics')] /** - * @summary Секция для отображения общей статистики. - * @param statistics Объект со статистическими данными. + * @summary Section for displaying general statistics. + * @param statistics The object with statistical data. */ @Composable private fun StatisticsSection(statistics: GroupStatistics) { @@ -164,9 +164,9 @@ private fun StatisticsSection(statistics: GroupStatistics) { // [ENTITY: Function('StatisticCard')] /** - * @summary Карточка для отображения одного статистического показателя. - * @param title Название показателя. - * @param value Значение показателя. + * @summary Card for displaying a single statistical indicator. + * @param title The name of the indicator. + * @param value The value of the indicator. */ @Composable private fun StatisticCard(title: String, value: String) { @@ -180,8 +180,8 @@ private fun StatisticCard(title: String, value: String) { // [ENTITY: Function('RecentlyAddedSection')] // [RELATION: Function('RecentlyAddedSection')] -> [DEPENDS_ON] -> [DataClass('ItemSummary')] /** - * @summary Секция для отображения недавно добавленных элементов. - * @param items Список элементов для отображения. + * @summary Section for displaying recently added items. + * @param items The list of items to display. */ @Composable private fun RecentlyAddedSection(items: List) { @@ -213,8 +213,8 @@ private fun RecentlyAddedSection(items: List) { // [ENTITY: Function('ItemCard')] // [RELATION: Function('ItemCard')] -> [DEPENDS_ON] -> [DataClass('ItemSummary')] /** - * @summary Карточка для отображения краткой информации об элементе. - * @param item Элемент для отображения. + * @summary Card for displaying brief information about an item. + * @param item The item to display. */ @Composable private fun ItemCard(item: ItemSummary) { @@ -236,9 +236,9 @@ private fun ItemCard(item: ItemSummary) { // [ENTITY: Function('LocationsSection')] // [RELATION: Function('LocationsSection')] -> [DEPENDS_ON] -> [DataClass('LocationOutCount')] /** - * @summary Секция для отображения местоположений в виде чипсов. - * @param locations Список местоположений. - * @param onLocationClick Лямбда-обработчик нажатия на местоположение. + * @summary Section for displaying locations as chips. + * @param locations The list of locations. + * @param onLocationClick A lambda handler for clicking on a location. */ @OptIn(ExperimentalLayoutApi::class) @Composable @@ -265,9 +265,9 @@ private fun LocationsSection(locations: List, onLocationClick: // [ENTITY: Function('LabelsSection')] // [RELATION: Function('LabelsSection')] -> [DEPENDS_ON] -> [DataClass('LabelOut')] /** - * @summary Секция для отображения меток в виде чипсов. - * @param labels Список меток. - * @param onLabelClick Лямбда-обработчик нажатия на метку. + * @summary Section for displaying labels as chips. + * @param labels The list of labels. + * @param onLabelClick A lambda handler for clicking on a label. */ @OptIn(ExperimentalLayoutApi::class) @Composable diff --git a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardUiState.kt b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardUiState.kt index 28b442e..baeda5a 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardUiState.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardUiState.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.dashboard // [FILE] DashboardUiState.kt -// [SEMANTICS] ui, state, dashboard +// [SEMANTICS] app, ui, state, dashboard package com.homebox.lens.ui.screen.dashboard // [IMPORTS] @@ -12,8 +12,8 @@ import com.homebox.lens.domain.model.LocationOutCount // [ENTITY: SealedInterface('DashboardUiState')] /** - * @summary Определяет все возможные состояния для экрана "Дэшборд". - * @invariant В любой момент времени экран может находиться только в одном из этих состояний. + * @summary Defines all possible states for the "Dashboard" screen. + * @invariant At any given time, the screen can only be in one of these states. */ sealed interface DashboardUiState { // [ENTITY: DataClass('Success')] @@ -22,11 +22,11 @@ sealed interface DashboardUiState { // [RELATION: DataClass('Success')] -> [DEPENDS_ON] -> [DataClass('LabelOut')] // [RELATION: DataClass('Success')] -> [DEPENDS_ON] -> [DataClass('ItemSummary')] /** - * @summary Состояние успешной загрузки данных. - * @param statistics Статистика по инвентарю. - * @param locations Список локаций со счетчиками. - * @param labels Список всех меток. - * @param recentlyAddedItems Список недавно добавленных товаров. + * @summary The state of a successful data load. + * @param statistics The inventory statistics. + * @param locations The list of locations with counters. + * @param labels The list of all labels. + * @param recentlyAddedItems The list of recently added items. */ data class Success( val statistics: GroupStatistics, @@ -38,15 +38,15 @@ sealed interface DashboardUiState { // [ENTITY: DataClass('Error')] /** - * @summary Состояние ошибки во время загрузки данных. - * @param message Человекочитаемое сообщение об ошибке. + * @summary The state of an error during data loading. + * @param message A human-readable error message. */ data class Error(val message: String) : DashboardUiState // [END_ENTITY: DataClass('Error')] // [ENTITY: Object('Loading')] /** - * @summary Состояние, когда данные для экрана загружаются. + * @summary The state when data for the screen is being loaded. */ data object Loading : DashboardUiState // [END_ENTITY: Object('Loading')] diff --git a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardViewModel.kt b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardViewModel.kt index 3acb812..0431f05 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardViewModel.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/dashboard/DashboardViewModel.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.dashboard // [FILE] DashboardViewModel.kt -// [SEMANTICS] ui_logic, dashboard, state_management, sealed_state, parallel_data_loading, timber_logging +// [SEMANTICS] app, ui, viewmodel, dashboard package com.homebox.lens.ui.screen.dashboard // [IMPORTS] @@ -24,10 +24,10 @@ import javax.inject.Inject // [RELATION: ViewModel('DashboardViewModel')] -> [DEPENDS_ON] -> [UseCase('GetRecentlyAddedItemsUseCase')] // [RELATION: ViewModel('DashboardViewModel')] -> [EMITS_STATE] -> [SealedInterface('DashboardUiState')] /** - * @summary ViewModel для главного экрана (Dashboard). - * @description Оркестрирует загрузку данных для Dashboard, используя строгую модель состояний - * (`DashboardUiState`), и обрабатывает параллельные запросы без состояний гонки. - * @invariant `uiState` всегда является одним из состояний, определенных в `DashboardUiState`. + * @summary ViewModel for the main screen (Dashboard). + * @description Orchestrates the loading of data for the Dashboard, using a strict state model + * (`DashboardUiState`), and handles parallel requests without race conditions. + * @invariant `uiState` is always one of the states defined in `DashboardUiState`. */ @HiltViewModel class DashboardViewModel @Inject constructor( @@ -46,10 +46,10 @@ class DashboardViewModel @Inject constructor( // [ENTITY: Function('loadDashboardData')] /** - * @summary Загружает все необходимые данные для экрана Dashboard. - * @description Выполняет UseCase'ы параллельно и обновляет UI, переключая его - * между состояниями `Loading`, `Success` и `Error` из `DashboardUiState`. - * @sideeffect Асинхронно обновляет `_uiState` одним из состояний `DashboardUiState`. + * @summary Loads all necessary data for the Dashboard screen. + * @description Executes UseCases in parallel and updates the UI by switching it + * between the `Loading`, `Success`, and `Error` states from `DashboardUiState`. + * @sideeffect Asynchronously updates `_uiState` with one of the `DashboardUiState` states. */ fun loadDashboardData() { viewModelScope.launch { diff --git a/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListScreen.kt index 3becc28..5d2c7d2 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListScreen.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.inventorylist // [FILE] InventoryListScreen.kt -// [SEMANTICS] ui, screen, inventory, list +// [SEMANTICS] app, ui, screen, list package com.homebox.lens.ui.screen.inventorylist @@ -17,9 +17,9 @@ import com.homebox.lens.ui.common.MainScaffold // [RELATION: Function('InventoryListScreen')] -> [DEPENDS_ON] -> [Class('NavigationActions')] // [RELATION: Function('InventoryListScreen')] -> [CALLS] -> [Function('MainScaffold')] /** - * @summary Composable-функция для экрана "Список инвентаря". - * @param currentRoute Текущий маршрут для подсветки активного элемента в Drawer. - * @param navigationActions Объект с навигационными действиями. + * @summary Composable function for the "Inventory List" screen. + * @param currentRoute The current route to highlight the active item in the Drawer. + * @param navigationActions The object with navigation actions. */ @Composable fun InventoryListScreen( diff --git a/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListViewModel.kt b/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListViewModel.kt index 6ddcc31..0eaf008 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListViewModel.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/inventorylist/InventoryListViewModel.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.inventorylist // [FILE] InventoryListViewModel.kt -// [SEMANTICS] ui, viewmodel, inventory_list +// [SEMANTICS] app, ui, viewmodel, list package com.homebox.lens.ui.screen.inventorylist // [IMPORTS] diff --git a/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsScreen.kt index 1feb48a..5435781 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsScreen.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.itemdetails // [FILE] ItemDetailsScreen.kt -// [SEMANTICS] ui, screen, item, details +// [SEMANTICS] app, ui, screen, details package com.homebox.lens.ui.screen.itemdetails @@ -17,9 +17,9 @@ import com.homebox.lens.ui.common.MainScaffold // [RELATION: Function('ItemDetailsScreen')] -> [DEPENDS_ON] -> [Class('NavigationActions')] // [RELATION: Function('ItemDetailsScreen')] -> [CALLS] -> [Function('MainScaffold')] /** - * @summary Composable-функция для экрана "Детали элемента". - * @param currentRoute Текущий маршрут для подсветки активного элемента в Drawer. - * @param navigationActions Объект с навигационными действиями. + * @summary Composable function for the "Item Details" screen. + * @param currentRoute The current route to highlight the active item in the Drawer. + * @param navigationActions The object with navigation actions. */ @Composable fun ItemDetailsScreen( diff --git a/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsViewModel.kt b/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsViewModel.kt index 104c5c3..a088d94 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsViewModel.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/itemdetails/ItemDetailsViewModel.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.itemdetails // [FILE] ItemDetailsViewModel.kt -// [SEMANTICS] ui, viewmodel, item_details +// [SEMANTICS] app, ui, viewmodel, details package com.homebox.lens.ui.screen.itemdetails // [IMPORTS] 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 85d40ff..0a05006 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 @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.itemedit // [FILE] ItemEditScreen.kt -// [SEMANTICS] ui, screen, item, edit +// [SEMANTICS] app, ui, screen, edit package com.homebox.lens.ui.screen.itemedit @@ -21,13 +21,17 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.Save +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DatePicker import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -38,6 +42,7 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -67,12 +72,12 @@ import java.util.Locale // [RELATION: Composable('ItemEditScreen')] -> [CONSUMES_STATE] -> [DataClass('ItemEditUiState')] // [RELATION: Composable('ItemEditScreen')] -> [CALLS] -> [Composable('MainScaffold')] /** - * @summary Composable-функция для экрана "Редактирование элемента". - * @param currentRoute Текущий маршрут для подсветки активного элемента в Drawer. - * @param navigationActions Объект с навигационными действиями. - * @param itemId ID элемента для редактирования. Null, если создается новый элемент. - * @param viewModel ViewModel для управления состоянием экрана. - * @param onSaveSuccess Callback, вызываемый после успешного сохранения товара. + * @summary Composable function for the "Edit Item" screen. + * @param currentRoute The current route to highlight the active item in the Drawer. + * @param navigationActions The object with navigation actions. + * @param itemId The ID of the item to edit. Null if a new item is being created. + * @param viewModel The ViewModel for managing the screen's state. + * @param onSaveSuccess A callback invoked after the item is successfully saved. */ @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -164,34 +169,124 @@ fun ItemEditScreen( keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), modifier = Modifier.fillMaxWidth() ) - Spacer(modifier = Modifier.height(8.dp)) - // [AI_NOTE]: Location selection will require a separate component or screen. - OutlinedTextField( - value = item.location?.name ?: "", - onValueChange = { /* TODO: Implement location selection */ }, - 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.item_edit_select_location)) - } - }, - modifier = Modifier.fillMaxWidth() - ) - Spacer(modifier = Modifier.height(8.dp)) - // [AI_NOTE]: Label selection will require a separate component or screen. - OutlinedTextField( - value = item.labels.joinToString { it.name }, - onValueChange = { /* TODO: Implement label selection */ }, - 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.item_edit_select_labels)) - } - }, - modifier = Modifier.fillMaxWidth() - ) + Spacer(modifier = Modifier.height(8.dp)) + + // Location Dropdown + var locationExpanded by remember { mutableStateOf(false) } + ExposedDropdownMenuBox( + expanded = locationExpanded, + onExpandedChange = { locationExpanded = !locationExpanded } + ) { + OutlinedTextField( + value = item.location?.name ?: "", + onValueChange = { }, + label = { Text(stringResource(R.string.item_edit_location)) }, + readOnly = true, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon(expanded = locationExpanded) + }, + modifier = Modifier + .fillMaxWidth() + .menuAnchor() + ) + ExposedDropdownMenu( + expanded = locationExpanded, + onDismissRequest = { locationExpanded = false } + ) { + uiState.allLocations.forEach { location -> + DropdownMenuItem( + text = { Text(location.name) }, + onClick = { + viewModel.updateLocation(location) + locationExpanded = false + } + ) + } + } + } + + Spacer(modifier = Modifier.height(8.dp)) + + // Labels Dialog + var showLabelsDialog by remember { mutableStateOf(false) } + + OutlinedTextField( + value = item.labels.joinToString { it.name }, + onValueChange = { }, + label = { Text(stringResource(R.string.item_edit_labels)) }, + readOnly = true, + modifier = Modifier + .fillMaxWidth() + .clickable { showLabelsDialog = true }, + trailingIcon = { + Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.item_edit_select_labels)) + } + ) + + if (showLabelsDialog) { + // This state will hold the temporary selections within the dialog + val tempSelectedLabels = remember { mutableStateOf(item.labels.toSet()) } + + AlertDialog( + onDismissRequest = { showLabelsDialog = false }, + title = { Text(stringResource(R.string.item_edit_select_labels)) }, + text = { + Column { + uiState.allLabels.forEach { label -> + val isChecked = tempSelectedLabels.value.contains(label) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .clickable { + val currentSelection = tempSelectedLabels.value.toMutableSet() + if (isChecked) { + currentSelection.remove(label) + } else { + currentSelection.add(label) + } + tempSelectedLabels.value = currentSelection + } + .padding(vertical = 8.dp) + ) { + Checkbox( + checked = isChecked, + onCheckedChange = { + val currentSelection = tempSelectedLabels.value.toMutableSet() + if (it) { + currentSelection.add(label) + } else { + currentSelection.remove(label) + } + tempSelectedLabels.value = currentSelection + } + ) + Text( + text = label.name, + modifier = Modifier.padding(start = 8.dp) + ) + } + } + } + }, + confirmButton = { + TextButton( + onClick = { + // Update the ViewModel with the final selection + viewModel.updateLabels(tempSelectedLabels.value.toList()) + showLabelsDialog = false + } + ) { + Text(stringResource(R.string.dialog_ok)) + } + }, + dismissButton = { + TextButton(onClick = { showLabelsDialog = false }) { + Text(stringResource(R.string.dialog_cancel)) + } + } + ) + } } } 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 3652b65..e898f2f 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 @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.itemedit // [FILE] ItemEditViewModel.kt -// [SEMANTICS] ui, viewmodel, item_edit +// [SEMANTICS] app, ui, viewmodel, edit package com.homebox.lens.ui.screen.itemedit @@ -16,6 +16,7 @@ import com.homebox.lens.domain.usecase.CreateItemUseCase import com.homebox.lens.domain.usecase.GetAllLabelsUseCase import com.homebox.lens.domain.usecase.GetAllLocationsUseCase import com.homebox.lens.domain.usecase.GetItemDetailsUseCase +import com.homebox.lens.data.mapper.toDomain import com.homebox.lens.domain.usecase.UpdateItemUseCase import com.homebox.lens.ui.mapper.ItemMapper import dagger.hilt.android.lifecycle.HiltViewModel @@ -59,6 +60,8 @@ data class ItemEditUiState( * @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 getAllLocationsUseCase Use case for fetching all locations. + * @param getAllLabelsUseCase Use case for fetching all labels. * @param itemMapper Mapper for converting between domain and UI item models. */ @HiltViewModel @@ -141,7 +144,7 @@ class ItemEditViewModel @Inject constructor( Timber.i("[INFO][ACTION][fetching_all_locations] Fetching all locations.") val allLocations = getAllLocationsUseCase().map { Location(it.id, it.name) } Timber.i("[INFO][ACTION][fetching_all_labels] Fetching all labels.") - val allLabels = getAllLabelsUseCase().map { Label(it.id, it.name) } + val allLabels = getAllLabelsUseCase().map { it.toDomain() } _uiState.value = _uiState.value.copy(allLocations = allLocations, allLabels = allLabels) Timber.i("[INFO][ACTION][all_locations_labels_fetched] Successfully fetched all locations and labels.") } catch (e: Exception) { diff --git a/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditScreen.kt index 8564ebc..0fbe1ca 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/labeledit/LabelEditScreen.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.labeledit // [FILE] LabelEditScreen.kt -// [SEMANTICS] ui, screen, label, edit +// [SEMANTICS] app, ui, screen, edit, label package com.homebox.lens.ui.screen.labeledit @@ -24,10 +24,10 @@ import com.homebox.lens.ui.components.LoadingOverlay // [ENTITY: Function('LabelEditScreen')] // [RELATION: Function('LabelEditScreen')] -> [DEPENDS_ON] -> [ViewModel('LabelEditViewModel')] /** - * @summary Composable-функция для экрана "Редактирование метки". - * @param labelId ID метки для редактирования или null для создания новой. - * @param onBack Навигация назад. - * @param onLabelSaved Действие после сохранения метки. + * @summary Composable function for the "Edit Label" screen. + * @param labelId The ID of the label to edit, or null to create a new one. + * @param onBack Navigation back. + * @param onLabelSaved Action after the label is saved. */ @OptIn(ExperimentalMaterial3Api::class) @Composable 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 453c23d..44c6996 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 @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.labeledit // [FILE] LabelEditViewModel.kt -// [SEMANTICS] ui, viewmodel, label_management +// [SEMANTICS] app, ui, viewmodel, edit, label package com.homebox.lens.ui.screen.labeledit diff --git a/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListScreen.kt b/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListScreen.kt index 8169827..e1f12f3 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListScreen.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListScreen.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.labelslist // [FILE] LabelsListScreen.kt -// [SEMANTICS] ui, labels_list, state_management, compose, dialog +// [SEMANTICS] app, ui, screen, list, label package com.homebox.lens.ui.screen.labelslist // [IMPORTS] @@ -46,10 +46,10 @@ import timber.log.Timber // [RELATION: Function('LabelsListScreen')] -> [DEPENDS_ON] -> [ViewModel('LabelsListViewModel')] // [RELATION: Function('LabelsListScreen')] -> [DEPENDS_ON] -> [Framework('NavController')] /** - * @summary Отображает экран со списком всех меток. - * @param currentRoute Текущий маршрут навигации. - * @param navigationActions Объект, содержащий действия по навигации. - * @param viewModel ViewModel, предоставляющая состояние UI для экрана меток. + * @summary Displays the screen with a list of all labels. + * @param currentRoute The current navigation route. + * @param navigationActions The object containing navigation actions. + * @param viewModel The ViewModel providing the UI state for the labels screen. */ @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -116,10 +116,10 @@ fun LabelsListScreen( // [ENTITY: Function('LabelsList')] // [RELATION: Function('LabelsList')] -> [DEPENDS_ON] -> [DataClass('Label')] /** - * @summary Composable-функция для отображения списка меток. - * @param labels Список объектов `Label` для отображения. - * @param onLabelClick Лямбда-функция, вызываемая при нажатии на элемент списка. - * @param modifier Модификатор для настройки внешнего вида. + * @summary Composable function for displaying a list of labels. + * @param labels The list of `Label` objects to display. + * @param onLabelClick A lambda function called when a list item is clicked. + * @param modifier A modifier for customizing the appearance. */ @Composable private fun LabelsList( @@ -145,9 +145,9 @@ private fun LabelsList( // [ENTITY: Function('LabelListItem')] // [RELATION: Function('LabelListItem')] -> [DEPENDS_ON] -> [DataClass('Label')] /** - * @summary Composable-функция для отображения одного элемента в списке меток. - * @param label Объект `Label`, который нужно отобразить. - * @param onClick Лямбда-функция, вызываемая при нажатии на элемент. + * @summary Composable function for displaying a single item in the list of labels. + * @param label The `Label` object to display. + * @param onClick A lambda function called when the item is clicked. */ @Composable private fun LabelListItem( diff --git a/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListUiState.kt b/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListUiState.kt index a53f005..c77235a 100644 --- a/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListUiState.kt +++ b/app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListUiState.kt @@ -1,6 +1,6 @@ // [PACKAGE] com.homebox.lens.ui.screen.labelslist // [FILE] LabelsListUiState.kt -// [SEMANTICS] ui_state, sealed_interface, contract +// [SEMANTICS] app, ui, state, list, label package com.homebox.lens.ui.screen.labelslist // [IMPORTS] @@ -9,17 +9,17 @@ import com.homebox.lens.domain.model.Label // [ENTITY: SealedInterface('LabelsListUiState')] /** - * @summary Определяет все возможные состояния для UI экрана со списком меток. - * @description Использование sealed-интерфейса позволяет исчерпывающе обрабатывать все состояния в Composable-функциях. + * @summary Defines all possible states for the UI of the screen with a list of labels. + * @description Using a sealed interface allows for exhaustive handling of all states in Composable functions. */ sealed interface LabelsListUiState { // [ENTITY: DataClass('Success')] // [RELATION: DataClass('Success')] -> [DEPENDS_ON] -> [DataClass('Label')] /** - * @summary Состояние успеха, содержит список меток и состояние диалога. - * @param labels Список меток для отображения. - * @param isShowingCreateDialog Флаг, показывающий, должен ли быть отображен диалог создания метки. - * @invariant labels не может быть null. + * @summary The success state, contains the list of labels and the state of the dialog. + * @param labels The list of labels to display. + * @param isShowingCreateDialog A flag indicating whether the label creation dialog should be displayed. + * @invariant labels cannot be null. */ data class Success( val labels: List