feat(android): album/photo attribute-actions and device gallery sync fixes
Album panel and photo sheet with attributes/actions for every album (server and device), local album rename/cover/delete, EXIF attribute settings, and a unified device-gallery sync check: - add repository "Атрибуты и действия" panel (swipe left) on server and device albums: cover, info, navigation, rename/delete; album settings screen; photo sheet (swipe up) with info, tags and actions; EXIF attribute settings backed by profile preferences - local albums use local metadata and actions: app-only display name and cover (new device_album_meta table), delete removes photos from the phone via the system delete consent - unified mode x state policy (GallerySyncPolicy/SyncCheck) runs on start and on album open: upload/offload in move, restore originals in copy/off - fix move->copy restore, offload of any linked-but-local original, provenance recovery that no longer overwrites the album mode, serialized reconcile and duplicate-upload suppression; prompt for "all files" access on start - album card caption: name (with linked server name when different) and storage icons (memory card / cloud) with item count Sync delta specs into android-client and archive the change add-mobile-album-photo-actions. Verified: unit/Robolectric suite green, :app:assembleDebug, :app:lint, and the DeviceSyncE2ETest instrumented suite on the emulator (7/7).
This commit is contained in:
@@ -356,3 +356,266 @@ SHALL выполняться свайпом.
|
||||
|
||||
- **WHEN** оригинал загружен или недоступен
|
||||
- **THEN** индикатор загрузки скрыт
|
||||
|
||||
### Requirement: Проверка доступа «Все файлы» при запуске
|
||||
Приложение SHALL при запуске, когда оно уже настроено и авторизовано, проверять наличие доступа
|
||||
«Все файлы» и при его отсутствии SHALL предлагать его включить, открывая системный экран настроек.
|
||||
|
||||
#### Scenario: Доступ не выдан
|
||||
- **WHEN** приложение запущено и доступ «Все файлы» не выдан
|
||||
- **THEN** показывается диалог с предложением включить доступ
|
||||
|
||||
#### Scenario: Включение доступа
|
||||
- **WHEN** пользователь подтверждает
|
||||
- **THEN** открывается системный экран выдачи доступа «Все файлы»
|
||||
|
||||
#### Scenario: Доступ уже выдан
|
||||
- **WHEN** доступ уже выдан
|
||||
- **THEN** диалог не показывается
|
||||
|
||||
### Requirement: Возврат оригиналов при выходе из переноса
|
||||
При переключении альбома из режима переноса в «копии» или «выключено» приложение SHALL
|
||||
возвращать оригиналы с сервера (когда пользователь выбирает возврат), а незавершённый возврат
|
||||
SHALL довосстанавливаться при следующей проверке (при запуске и при открытии альбома).
|
||||
|
||||
#### Scenario: Перенос → копии
|
||||
- **WHEN** пользователь переключает альбом из переноса в копии и подтверждает возврат оригиналов
|
||||
- **THEN** оригиналы скачиваются с сервера и заменяют превью на устройстве
|
||||
|
||||
#### Scenario: Довосстановление
|
||||
- **WHEN** альбом не в режиме переноса, но содержит превью с серверным фото
|
||||
- **THEN** при запуске или открытии альбома оригиналы довосстанавливаются
|
||||
|
||||
#### Scenario: Перенос → выключено
|
||||
- **WHEN** пользователь переключает перенос в выключено
|
||||
- **THEN** предлагается вернуть оригиналы или оставить превью
|
||||
|
||||
### Requirement: Единая проверка соответствия режиму
|
||||
При запуске и при открытии альбома приложение SHALL приводить локальное содержимое в
|
||||
соответствие режиму для всех сочетаний состояния ассета: в «переносе» разгружать уже загруженные
|
||||
оригиналы, а в «копиях»/«выключено» восстанавливать превью; отсутствующий локальный индекс SHALL
|
||||
восстанавливаться по метке происхождения.
|
||||
|
||||
#### Scenario: Копии с разгруженными файлами
|
||||
- **WHEN** альбом в режиме копий, а часть файлов разгружена (превью)
|
||||
- **THEN** проверка восстанавливает оригиналы
|
||||
|
||||
#### Scenario: Перенос с неразгруженными файлами
|
||||
- **WHEN** альбом в режиме переноса, файл есть на сервере, но оригинал ещё на телефоне
|
||||
- **THEN** проверка разгружает оригинал
|
||||
|
||||
#### Scenario: Потерянный индекс
|
||||
- **WHEN** у разгруженного медиа нет записи в локальном индексе
|
||||
- **THEN** связь и происхождение восстанавливаются по метке в файле
|
||||
|
||||
#### Scenario: Выключенный режим
|
||||
- **WHEN** альбом без синхронизации содержит превью
|
||||
- **THEN** оригиналы восстанавливаются, а сервер не затрагивается
|
||||
|
||||
### Requirement: Отсутствие дублей и гонок при синхронизации
|
||||
Проверка синхронизации SHALL выполняться последовательно (без одновременных проходов по одной
|
||||
галерее) и SHALL NOT ставить повторную загрузку, пока по тому же элементу уже есть задание в
|
||||
очереди. Метка происхождения в разгруженном файле SHALL хранить режим синхронизации, а не
|
||||
состояние элемента, чтобы восстановление не меняло режим галереи.
|
||||
|
||||
#### Scenario: Повторная проверка во время загрузки
|
||||
- **WHEN** проверка запускается снова, пока загрузка элемента ещё стоит в очереди
|
||||
- **THEN** повторная загрузка не ставится
|
||||
|
||||
#### Scenario: Метка происхождения хранит режим
|
||||
- **WHEN** разгруженный файл восстанавливается после переустановки
|
||||
- **THEN** режим галереи берётся из метки как режим (перенос/копии), а не как состояние элемента
|
||||
|
||||
### Requirement: Подпись карточки альбома
|
||||
Карточка альбома SHALL показывать в первой строке имя альбома, а для связанной пары — со
|
||||
стрелкой имя связанного серверного альбома, и только когда имена различаются. Вторая строка
|
||||
SHALL показывать значками расположение содержимого и число элементов: значок карты памяти для
|
||||
локального без синхронизации, значки карты памяти и облака для режима копий, значок облака для
|
||||
режима переноса; для серверного альбома — значок облака.
|
||||
|
||||
#### Scenario: Локальный без синхронизации
|
||||
- **WHEN** показан локальный альбом без синхронизации
|
||||
- **THEN** вторая строка показывает значок карты памяти и число элементов
|
||||
|
||||
#### Scenario: Режим копий
|
||||
- **WHEN** локальный альбом синхронизируется в режиме копий
|
||||
- **THEN** вторая строка показывает значки карты памяти и облака и число элементов
|
||||
|
||||
#### Scenario: Режим переноса
|
||||
- **WHEN** локальный альбом синхронизируется в режиме переноса
|
||||
- **THEN** вторая строка показывает значок облака и число элементов
|
||||
|
||||
#### Scenario: Разные имена связанной пары
|
||||
- **WHEN** имя локального альбома не совпадает с именем связанного серверного
|
||||
- **THEN** первая строка показывает «имя → имя серверного»
|
||||
|
||||
#### Scenario: Одинаковые имена
|
||||
- **WHEN** имена совпадают
|
||||
- **THEN** стрелка и имя серверного не показываются
|
||||
|
||||
### Requirement: Панель атрибутов и действий альбома
|
||||
Приложение SHALL открывать панель «Атрибуты и действия» по свайпу справа налево на экране
|
||||
любого альбома — серверного и локального. Панель SHALL повторять структуру web: разделы
|
||||
«Обложка», «Информация», «Навигация» и раздел «Действия».
|
||||
|
||||
#### Scenario: Открытие свайпом
|
||||
- **WHEN** пользователь свайпает справа налево в открытом альбоме
|
||||
- **THEN** открывается панель «Атрибуты и действия»
|
||||
|
||||
#### Scenario: Структура панели
|
||||
- **WHEN** панель открыта
|
||||
- **THEN** показаны разделы «Обложка», «Информация», «Навигация» и «Действия»
|
||||
|
||||
#### Scenario: Закрытие панели
|
||||
- **WHEN** пользователь закрывает панель (свайп в обратную сторону или касание вне панели)
|
||||
- **THEN** панель скрывается, сетка медиа снова доступна
|
||||
|
||||
### Requirement: Источник атрибутов локального альбома
|
||||
Для локального альбома приложение SHALL показывать ту же панель «Атрибуты и действия», что и
|
||||
для серверного, а метаданные SHALL брать локально (имя, число элементов, локальная обложка,
|
||||
режим синхронизации, связанный серверный альбом). Действия локального альбома SHALL
|
||||
применяться локально.
|
||||
|
||||
#### Scenario: Локальные метаданные
|
||||
- **WHEN** пользователь открывает панель локального альбома
|
||||
- **THEN** раздел «Информация» показывает локальные имя, число элементов и обложку
|
||||
|
||||
#### Scenario: Неактивная навигация без связи
|
||||
- **WHEN** локальный альбом не связан с серверным
|
||||
- **THEN** строки «Участники» и «Ссылки для просмотра» показаны, но неактивны
|
||||
|
||||
#### Scenario: Активная навигация при связи
|
||||
- **WHEN** локальный альбом связан с серверным
|
||||
- **THEN** строки «Участники» и «Ссылки для просмотра» активны и относятся к связанному серверному альбому
|
||||
|
||||
### Requirement: Переименование и обложка локального альбома
|
||||
Для локального альбома действие «Переименовать» SHALL менять отображаемое имя в приложении, не
|
||||
изменяя медиа или bucket на устройстве, а «Выбрать обложку»/«Сбросить» SHALL назначать или
|
||||
снимать обложку из медиа этого альбома. Имя и обложка SHALL храниться локально.
|
||||
|
||||
#### Scenario: Переименование
|
||||
- **WHEN** пользователь вводит новое имя локального альбома
|
||||
- **THEN** панель, заголовок и карточка в списке альбомов показывают новое имя
|
||||
|
||||
#### Scenario: Назначение и сброс обложки
|
||||
- **WHEN** пользователь выбирает медиа обложкой или сбрасывает её
|
||||
- **THEN** панель и карточка альбома отражают выбор
|
||||
|
||||
### Requirement: Удаление локального альбома с телефона
|
||||
Действие «Удалить» локального альбома SHALL после подтверждения удалять все фото и видео
|
||||
этого альбома с устройства, запрашивая при необходимости системное согласие.
|
||||
|
||||
#### Scenario: Подтверждение
|
||||
- **WHEN** пользователь выбирает «Удалить» локального альбома
|
||||
- **THEN** открывается диалог с предупреждением, что медиа будут удалены с телефона
|
||||
|
||||
#### Scenario: Удаление
|
||||
- **WHEN** пользователь подтверждает удаление
|
||||
- **THEN** медиа удаляются с устройства, а альбом исчезает из приложения
|
||||
|
||||
### Requirement: Атрибуты альбома
|
||||
Панель SHALL показывать обложку с выбором и сбросом, информацию (название, описание, число
|
||||
фото и участников) и переходы к участникам, настройкам и ссылкам для просмотра. Управление
|
||||
обложкой и раздел «Навигация» SHALL быть доступны только владельцу и администратору.
|
||||
|
||||
#### Scenario: Управление обложкой
|
||||
- **WHEN** владелец или администратор выбирает или сбрасывает обложку
|
||||
- **THEN** изменение сохраняется на сервере и отражается в списке и панели
|
||||
|
||||
#### Scenario: Наблюдатель
|
||||
- **WHEN** наблюдатель открывает панель
|
||||
- **THEN** управление обложкой не показывается, а строки «Настройки» и «Ссылки для просмотра» неактивны
|
||||
|
||||
#### Scenario: Переход к настройкам
|
||||
- **WHEN** владелец или администратор открывает настройки из раздела «Навигация»
|
||||
- **THEN** доступны правка названия и описания и управление ссылками для просмотра
|
||||
|
||||
### Requirement: Действия с альбомом
|
||||
Панель SHALL содержать действия «Переименовать» и «Удалить». Удаление SHALL подтверждаться
|
||||
диалогом, а удалённый альбом SHALL помещать свои фото в корзину.
|
||||
|
||||
#### Scenario: Переименование
|
||||
- **WHEN** владелец или администратор выбирает «Переименовать» и вводит новое название
|
||||
- **THEN** название сохраняется на сервере и отражается в списке и заголовке
|
||||
|
||||
#### Scenario: Удаление с подтверждением
|
||||
- **WHEN** владелец выбирает «Удалить» и подтверждает в диалоге
|
||||
- **THEN** альбом удаляется, а его фото попадают в корзину
|
||||
|
||||
### Requirement: Лист атрибутов и действий фото
|
||||
Полноэкранный просмотр SHALL открывать лист «Атрибуты и действия» по свайпу вверх как в
|
||||
серверном, так и в device-просмотре. Лист SHALL повторять структуру web: разделы
|
||||
«Информация», «Метки» и «Действия». При зуме изображения, панораме или активном управлении
|
||||
видео свайп вверх SHALL NOT открывать лист.
|
||||
|
||||
#### Scenario: Открытие листа
|
||||
- **WHEN** пользователь свайпает вверх во вписанном изображении
|
||||
- **THEN** открывается лист «Атрибуты и действия» для текущего элемента
|
||||
|
||||
#### Scenario: Зум или панорама
|
||||
- **WHEN** изображение увеличено или открыта панорама, и пользователь свайпает вверх
|
||||
- **THEN** лист не открывается, жест обрабатывается изображением
|
||||
|
||||
#### Scenario: Видео
|
||||
- **WHEN** открыт видеоэлемент, и пользователь взаимодействует с плеером
|
||||
- **THEN** свайп вверх не мешает управлению воспроизведением
|
||||
|
||||
### Requirement: Атрибуты фото в листе
|
||||
Раздел «Информация» SHALL показывать автора, размер файла, тип, разрешение, EXIF-атрибуты,
|
||||
дату съёмки, координаты и дату загрузки. Раздел «Метки» SHALL позволять добавлять и снимать
|
||||
метки с поиском по меткам пользователя и созданием новых.
|
||||
|
||||
#### Scenario: Информация
|
||||
- **WHEN** лист открыт
|
||||
- **THEN** раздел «Информация» показывает метаданные и EXIF текущего фото
|
||||
|
||||
#### Scenario: Метки
|
||||
- **WHEN** пользователь добавляет или снимает метку в разделе «Метки»
|
||||
- **THEN** изменение сразу отражается в просмотре без перезагрузки
|
||||
|
||||
### Requirement: Настройки списка атрибутов
|
||||
Раздел «Информация» SHALL давать доступ к настройкам со списком EXIF-атрибутов, где
|
||||
пользователь отмечает отображаемые атрибуты и задаёт их подписи, с действиями «отметить все»
|
||||
и «снять все». Настройки SHALL применяться ко всем фото и сохраняться в профиле пользователя.
|
||||
|
||||
#### Scenario: Открытие настроек
|
||||
- **WHEN** пользователь открывает настройки атрибутов
|
||||
- **THEN** показан список EXIF-атрибутов с галочками видимости и полями подписей
|
||||
|
||||
#### Scenario: Сохранение настроек
|
||||
- **WHEN** пользователь отмечает атрибуты, задаёт подписи и сохраняет
|
||||
- **THEN** настройки сохраняются в профиле и применяются в разделе «Информация»
|
||||
|
||||
#### Scenario: Сброс настроек
|
||||
- **WHEN** пользователь сбрасывает настройки
|
||||
- **THEN** применяется базовый набор атрибутов с исходными подписями
|
||||
|
||||
### Requirement: Действия с фото в листе
|
||||
Раздел «Действия» SHALL содержать «Скачать», «Переместить», «Копировать», «Установить как
|
||||
обложку альбома» (по правам) и «Удалить»; из сетки также «Открыть (просмотр)». Удаление SHALL
|
||||
подтверждаться диалогом. Переименование SHALL выполняться по тапу на имя файла.
|
||||
|
||||
#### Scenario: Состав действий
|
||||
- **WHEN** лист открыт
|
||||
- **THEN** показаны действия «Скачать», «Переместить», «Копировать», «Установить как обложку» и «Удалить» по правам
|
||||
|
||||
#### Scenario: Удаление фото
|
||||
- **WHEN** пользователь выбирает «Удалить» и подтверждает
|
||||
- **THEN** фото уходит в корзину, а просмотр переходит к соседнему элементу
|
||||
|
||||
#### Scenario: Переименование фото
|
||||
- **WHEN** автор, владелец или администратор меняет имя файла на непустое
|
||||
- **THEN** новое имя сохраняется и отражается в просмотре и сетке
|
||||
|
||||
### Requirement: Источник атрибутов device-медиа
|
||||
Для device-медиа приложение SHALL показывать атрибуты и действия сопоставленного серверного
|
||||
фото, когда сопоставление есть, и локальные атрибуты и действия (имя, размер, тип,
|
||||
разрешение, дата, путь) при его отсутствии.
|
||||
|
||||
#### Scenario: Сопоставлено серверному фото
|
||||
- **WHEN** device-медиа сопоставлено серверному фото
|
||||
- **THEN** лист показывает серверные атрибуты и серверные действия этого фото
|
||||
|
||||
#### Scenario: Не сопоставлено
|
||||
- **WHEN** сопоставления с серверным фото нет
|
||||
- **THEN** лист показывает локальные атрибуты и локальные действия элемента
|
||||
|
||||
Reference in New Issue
Block a user