MODIFY_CODE app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListScreen.kt Реализовать UI для экрана "Метки" (`LabelsListScreen`) в соответствии со спецификацией `screen_labels_list`. Это включает в себя создание Composable-функции, которая: 1. Использует `Scaffold` с `TopAppBar` и `FloatingActionButton`. 2. Получает состояние (список меток, статус загрузки, ошибки) от `LabelsListViewModel`. 3. Отображает список меток с помощью `LazyColumn`. 4. Обрабатывает клики по элементам списка для навигации на экран инвентаря с фильтром по метке. 5. Обрабатывает нажатие на FAB для создания новой метки (пока что через лог). 6. Отображает индикатор загрузки и сообщения об ошибках или пустом списке. 7. Строго следует принципам Design by Contract, использует иконки из гайда и строки из ресурсов. PROJECT_SPECIFICATION.xml PROJECT_STRUCTURE.xml app/src/main/java/com/homebox/lens/ui/screen/labelslist/LabelsListViewModel.kt domain/src/main/java/com/homebox/lens/domain/model/Label.kt app/src/main/java/com/homebox/lens/navigation/Screen.kt // [CORE-LOGIC] Box( modifier = Modifier .fillMaxSize() .padding(paddingValues), contentAlignment = Alignment.Center ) { when { uiState.isLoading -> { // [STATE_BRANCH] Loading CircularProgressIndicator() } uiState.error != null -> { // [STATE_BRANCH] Error Text(text = uiState.error ?: stringResource(id = R.string.error_unknown)) } uiState.labels.isEmpty() -> { // [STATE_BRANCH] Empty Text(text = stringResource(id = R.string.labels_list_empty)) } else -> { // [STATE_BRANCH] Success LabelsList( labels = uiState.labels, onLabelClick = { label -> // [ACTION] // TODO: Реализовать навигацию на экран инвентаря с фильтром logger.info { "[ACTION] Label clicked: ${label.id}. Navigating to inventory list." } // navController.navigate(Screen.InventoryList.withFilter("label", label.id)) } ) } } } } // [COHERENCE_CHECK_PASSED] } // [END_FUNCTION] LabelsListScreen // [HELPER] /** * [CONTRACT] * Composable-функция для отображения списка меток. * * @param labels Список объектов `Label` для отображения. * @param onLabelClick Лямбда-функция, вызываемая при нажатии на элемент списка. * * @precondition `labels` не должен быть null. * @postcondition Отображается вертикальный прокручиваемый список. */ @Composable private fun LabelsList( labels: List Используйте `@HiltViewModel` для получения экземпляра `LabelsListViewModel`. Собирайте `uiState` из ViewModel с помощью `collectAsState()` для автоматического обновления UI при изменении состояния. Используйте `Scaffold` для базовой структуры экрана (TopAppBar, FAB, основное содержимое). Для навигации назад используйте `navController.navigateUp()`. Используйте `LazyColumn` для эффективного отображения потенциально длинных списков меток. Обязательно добавьте новые строковые ресурсы (`screen_title_labels`, `content_desc_navigate_back`, `content_desc_create_label`, `labels_list_empty`, `content_desc_label_icon`) в `strings.xml`. Иконки должны браться из `androidx.compose.material.icons` в соответствии с `ICONOGRAPHY_GUIDE`.