feat(android): статус синхронизации на карточке и безопасная разгрузка

Карточка альбома устройства получает третью строку: метку режима («Копии»/
«Перенос») и ход загрузки. Процент считается как (uploaded + running) / total
для обоих синхронизируемых режимов, пульсирует только при активной загрузке,
показывает очередь, ожидание Wi-Fi и ошибку. В режиме переноса карточка
показывает и карту памяти, и облако — режимы различает метка, а не значки.

Разгрузка оригиналов теперь требует подтверждённой серверной копии в текущем
целевом альбоме: устаревший serverPhotoId перепроверяется по альбому, смена
цели переносит уже загруженные фото и отклоняется, если перенести нельзя.
Потеря серверной копии видна на карточке и на экране альбома, автозатирания
превью нет.

Изменения OpenSpec: android-album-card-sync-status, safe-album-offload.
This commit is contained in:
iu
2026-10-16 18:36:51 +03:00
parent 98aaa3156a
commit 1eb1177273
36 changed files with 1855 additions and 81 deletions
@@ -0,0 +1,62 @@
# Proposal
## Why
Карточка альбома в Android-клиенте кодирует режим синхронизации одними значками, и это
перестало быть информативным. В режиме переноса (C) на телефоне остаются превью, но
карточка показывает только облако — «локальной копии» не видно. Добавить карте памяти в C
нельзя без последствий: тогда карты памяти и облако будут у копий (B) и переноса (C)
одинаковы, и режимы станут неразличимы.
Отдельно невидим прогресс копирования (B). Единственный след работы — счётчик в рейле и
экран «Загрузки»; на самой карточке не понять, сколько уже на сервере, идёт ли заливка,
ждёт ли она Wi‑Fi или упала. Провал заливки сейчас вообще не проявляется в списке альбомов.
## What Changes
- Карточка альбома устройства получает **метку режима** третьей строкой: «Копии» для B,
«Перенос» для C, ничего для выключенной синхронизации (A) и серверных альбомов.
- Карта памяти (SD) теперь показывается и для режима переноса: `[SD][Cloud]`. Режимы
различаются не значками, а меткой режима, поэтому SD читается как «есть локальная копия»
(оригинал в B, превью в C).
- Для режима копий третья строка показывает **процент операции**, пока заливка активна:
`«Копии 62%»`. Текст процента пульсирует, пока есть работающие загрузки.
- Состояния вместо/рядом с процентом: `«Копии 8 в очереди»` для ожидающих, `«Копии — ждёт
Wi‑Fi»` для ожидающих по ограничению сети, `«Копии — ошибка»` при провале, просто
`«Копии»` в простое.
- Процент считается по альбому: `(uploaded + running) / total`, где `uploaded` — записи
индекса провенанса с серверным фото, `running` — дроби `progress/100` работающих загрузок,
`total` — число элементов альбома устройства. Формула держит монотонность и не «едет
назад» при завершении файлов.
- Пульсация включается только при наличии работающей загрузки, поэтому альбом, ждущий
Wi‑Fi, не выглядит как активный.
- **BREAKING**: нет. Для серверных альбомов и выключенной синхронизации карточка не меняется;
меняется только вид карточек альбомов устройства с включённой синхронизацией.
## Capabilities
### New Capabilities
_Нет — поведение расширяет существующую способность `android-client`._
### Modified Capabilities
- `android-client`: требование «Подпись карточки альбома» переформулируется (метка режима
третьей строкой; карта памяти показывается и для переноса) и дополняется новым
требованием о прогрессе операции копирования с его состояниями.
## Impact
- **Код (Android):** `ui/albums/AlbumListItem` (модель строки: метка режима и прогресс),
`ui/albums/AlbumListBuilder` (сборка прогресса в элемент списка), `ui/albums/AlbumsViewModel`
(агрегат очереди загрузок и индекса), `ui/albums/AlbumsScreen` (`AlbumCardBody`: третья
строка, пульсация), доменная модель `domain/model/Upload` (поле привязки к альбому
устройства), `data/upload/UploadRepository`, `data/db/dao/UploadDao` и `SyncDao`
(счётные запросы по альбому).
- **Схема Room:** новых таблиц/колонок не требуется — `upload_jobs.deviceAlbumId` и
`device_assets` уже хранят всё нужное; добавляются только запросы.
- **API и бэкенд:** не затрагиваются.
- **Веб-клиент:** не затрагивается.
- **Не затрагивается / отдельно:** прогресс в фазе загрузки режима переноса (C) — тот же
механизм применим, но в объём этого изменения не входит; ручные загрузки в серверный
альбом на карточке не отражаются (у них нет привязки к альбому устройства).