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,82 @@
# Spec Delta
## MODIFIED Requirements
### Requirement: Разгрузка оригиналов в режиме переноса
В режиме C после успешной загрузки приложение SHALL автоматически заменять оригинал
на устройстве превью, без отдельного действия на экране, но SHALL делать это только если
серверная копия подтверждена в текущем целевом альбоме; видео SHALL заменяться
постером-кадром. При включении режима C приложение SHALL запрашивать широкий доступ
к файлам, чтобы замена выполнялась без системного диалога согласия.
#### Scenario: Разгрузка фото
- **WHEN** оригинал фото успешно загружен
- **THEN** файл в галерее автоматически заменяется превью с сохранением даты съёмки и места в альбоме
#### Scenario: Разгрузка видео
- **WHEN** оригинал видео успешно загружен
- **THEN** видео в галерее автоматически заменяется статичным постером-кадром, а элемент в приложении остаётся видео с оригиналом на сервере
#### Scenario: Доступ к файлам для разгрузки
- **WHEN** пользователь включает режим переноса
- **THEN** приложение запрашивает широкий доступ к файлам, и разгрузка выполняется без системного диалога согласия
#### Scenario: Копия не подтверждена
- **WHEN** серверная копия ассета отсутствует в текущем целевом альбоме
- **THEN** оригинал на устройстве не заменяется превью
## ADDED Requirements
### Requirement: Доверие только к живой серверной копии
Приложение SHALL считать записанный идентификатор серверного фото действительным только
если это фото присутствует в целевом альбоме. Если копии в целевом альбоме нет, приложение
SHALL при локальном оригинале загрузить ассет заново, а при одном локальном превью SHALL
пометить элемент как потерявший серверную копию.
#### Scenario: Копия пропала, оригинал локально
- **WHEN** записанное серверное фото ассета отсутствует в целевом альбоме, а оригинал ещё на устройстве
- **THEN** приложение загружает ассет в целевой альбом заново
#### Scenario: Копия пропала, локально только превью
- **WHEN** записанное серверное фото ассета отсутствует в целевом альбоме, а на устройстве только превью
- **THEN** ассет не загружается повторно и помечается как потерявший серверную копию
#### Scenario: Копия есть
- **WHEN** записанное серверное фото присутствует в целевом альбоме
- **THEN** ассет считается синхронизированным, и повторной загрузки не происходит
#### Scenario: Чужое фото не удаляется
- **WHEN** ассет исчез с устройства, а его записанное серверное фото не принадлежит целевому альбому
- **THEN** приложение не удаляет это фото на сервере
### Requirement: Перенос копий при смене целевого альбома
При смене целевого серверного альбома приложение SHALL перенести в новый альбом уже
загруженные этим альбомом устройства фото и SHALL переключить связь только если все
копии, доступные в прежнем альбоме, оказались в новом. Если перенести нельзя, связь
SHALL остаться прежней, а пользователь SHALL получить уведомление об отказе.
#### Scenario: Перенос удался
- **WHEN** пользователь выбирает новый целевой альбом, а прежние загрузки доступны
- **THEN** приложение переносит их в новый альбом и переключает связь
#### Scenario: Прежний альбом недоступен
- **WHEN** прежний целевой альбом удалён или недоступен
- **THEN** связь не меняется, и пользователь уведомляется, что фото перенести не удалось
#### Scenario: Часть копий перенести нельзя
- **WHEN** часть прежних загрузок недоступна для переноса
- **THEN** связь не переключается, и пользователь уведомляется, сколько фото не удалось перенести