# Design ## Context См. `proposal.md` — мотивация. Ограничения, определяющие подход: - Порядок задавался запросом `AlbumDao.observeAll()` (`ORDER BY updatedAt DESC, title ASC`) — из UI его не изменить, а серверный порядок (`created_at DESC`) клиентом не использовался. - Список смешанный: `AlbumListBuilder` собирал два блока — карточки альбомов устройства, а под ними серверные (связанный серверный альбом скрывался, его показывала карточка устройства). - `DeviceAlbum` (MediaStore-бакет) содержит `name`, `itemCount`, `coverUri`, `relativePath`, но **не содержит дат**; дата элемента есть у `DeviceMedia` (`dateTaken`, `dateModified`). - `DeviceMediaMapping.albums` уже вычисляет «самый свежий элемент» бакета, чтобы выбрать обложку, — эту же величину можно взять как дату изменения альбома устройства. - Локальные настройки отображения живут в DataStore (`SettingsRepository`); на вебе аналоги — плотность сетки и тема. - Серверные `users.preferences` заменяются целиком, поэтому настройка отображения туда не идёт (см. решение 1 прошлой редакции). ## Goals / Non-Goals **Goals:** - Один порядок для всего списка, включая альбомы устройства, и обратный порядок к нему. - Сохранять выбор на устройстве и не менять поведение по умолчанию. **Non-Goals:** - Синхронизация выбора между устройствами. - Сортировка на вебе и на сервере. - Отдельные варианты «по дате создания»: у альбома устройства нет даты создания бакета. ## Decisions **1. Один общий список, а не два блока.** Карточки альбомов устройства и серверных альбомов упорядочиваются вместе по выбранному ключу; источник и раньше был виден по иконкам (карта памяти / облако), поэтому группировка по источнику ничего не добавляла, а сортировка «по названию» в двух блоках выглядела несортированной. Связанная пара остаётся одной карточкой устройства и участвует в порядке как она. Альтернатива — сортировать каждый блок отдельно, оставив устройство сверху: меньше правок, но выбранный порядок не выполнялся бы для половины списка. **2. Дата альбома устройства — самый свежий его элемент.** `DeviceMediaMapping` уже выбирает самый свежий элемент для обложки; то же значение становится датой изменения альбома и попадает в `DeviceAlbum`. Дополнительных запросов к MediaStore не нужно — данные уже в курсоре. Альтернативы: `MAX(date_modified)` отдельным запросом (лишний проход по провайдеру); брать только `device_assets` из Room (там лишь файлы, которые приложение уже обрабатывало, — дата была бы почти всегда пустой). **3. Направление — отдельный флаг поверх ключа.** Хранится пара «ключ + обратный порядок», а не шесть независимых вариантов: меню остаётся коротким, а переключатель «Обратный порядок» относится к любому ключу. Натуральные направления: время изменения и число фото — по убыванию, название — по возрастанию; обратный порядок инвертирует выбранное. Альтернатива — шесть пунктов меню: нагляднее, но перегружает панель. **4. Сравнение — по общим ключам карточки, в сборщике списка.** `AlbumListBuilder` строит единый компаратор по паре «заголовок / число элементов / дата изменения», которую умеет выдать и карточка устройства, и серверная. Серверную дату (`updatedAt`, ISO-8601) приводит к миллисекундам доменная функция; отсутствующая дата уходит в конец. Сортировка остаётся в сборщике, а Room — хранилищем без собственного порядка. Альтернатива — отдельный запрос на каждый режим в `AlbumDao`: размножение запросов и жёсткая связь сортировки с кэшем. **5. Хранение — узкий порт `AlbumSortPreference` поверх DataStore.** Пара «ключ + направление» читается и пишется через `AlbumSortPreference` (`SettingsRepository` его реализует). Узость важна не только стилистически: она позволила тестам ViewModel не поднимать DataStore, из-за чего несколько его экземпляров на одном файле в одной JVM встают на файловой блокировке. Альтернатива — читать настройки из общего `SettingsState`: шире зависимость и та же проблема в тестах. ## Risks / Trade-offs - **Смешение источников в одном списке** → карточка устройства и серверная карточка могут стоять рядом; источник различается иконками, а связанная пара по-прежнему одна карточка. - **Альбом устройства без элементов** (пустой бакет) не имеет даты → попадает в конец при сортировке по времени изменения. - **Разбор ISO-даты серверного альбома** может не удаться (неожиданный формат) → такая карточка уходит в конец, а не ломает сравнение. - **Настройка не переносится на другое устройство** → принято: это настройка отображения, а не пользовательские данные. ## Migration Plan Изменение аддитивное: новая пара настроек в DataStore со значением по умолчанию (по времени изменения, без обратного порядка), схема Room и API не меняются. Откат — предыдущая версия APK, при которой список снова упорядочен только по времени изменения, а альбомы устройства закреплены сверху.