Дельта перенесена в основные спеки: android-client («Прогресс восстановления оригиналов») и phone-album-sync («Ход и устойчивость восстановления оригиналов»). Изменение перемещено в openspec/changes/archive/2026-10-16-android-album-restore-progress.
51 KiB
android-client Specification
Purpose
Android-клиент для self-hosted galo: настройка подключения к серверу, авторизация, просмотр альбомов и медиа, а также фоновая загрузка фотографий и видео с телефона с офлайн-кэшем.
Requirements
Requirement: Настройка подключения к серверу
Приложение SHALL требовать явного указания базового URL инстанса galo при первом запуске и SHALL проверять доступность сервера перед переходом к работе.
Scenario: Успешная настройка
- WHEN пользователь вводит достижимый базовый URL и подтверждает
- THEN приложение проверяет
GET /api/healthи при успехе переходит к входу
Scenario: Сервер недоступен
- WHEN сервер недоступен или health вернул ошибку
- THEN приложение показывает ошибку и остаётся на экране настройки, сохраняя введённый URL
Requirement: Небезопасное соединение по LAN
Приложение SHALL по умолчанию запрещать незашифрованный HTTP и SHALL разрешать его только после явного включения пользователем режима небезопасного соединения.
Scenario: HTTP без разрешения
- WHEN пользователь указывает
http-URL и режим небезопасного соединения выключен - THEN приложение блокирует подключение и предлагает включить режим
Scenario: Режим включён
- WHEN пользователь включил режим небезопасного соединения
- THEN HTTP-подключение разрешено, а интерфейс явно отмечает небезопасное соединение
Requirement: Разрешение относительных URL объектов
Приложение SHALL трактовать относительные URL объектов из REST-ответов и SSE как пути на выбранном базовом URL сервера.
Scenario: Отдача объекта
- WHEN API возвращает
thumb_urlвида/api/objects/<key>?... - THEN приложение запрашивает объект с того же инстанса, что и базовый URL
Requirement: Вход и хранение сессии
Приложение SHALL позволять вход и регистрацию по email и паролю и SHALL хранить токены только в защищённом хранилище платформы.
Scenario: Успешный вход
- WHEN вход проходит успешно
- THEN токены сохраняются в защищённом хранилище, пользователь видит список альбомов
Scenario: Перезапуск с сессией
- WHEN приложение перезапущено с сохранённой сессией
- THEN пользователь остаётся авторизованным без повторного ввода пароля
Requirement: Автоматическое обновление токена
Приложение SHALL автоматически обновлять access-токен при ответе 401, пока refresh-токен действителен, и SHALL завершать сессию при неудачном обновлении.
Scenario: Прозрачное обновление
- WHEN запрос получает 401 и refresh-токен действителен
- THEN приложение обновляет токен и повторяет исходный запрос без участия пользователя
Scenario: Обновление не удалось
- WHEN обновление токена завершилось ошибкой
- THEN сессия очищается и пользователь возвращается на экран входа
Requirement: Список альбомов
Приложение SHALL показывать доступные пользователю альбомы одним смешанным списком: серверные альбомы, получаемые из API, а при отсутствии сети — из локального кэша, и альбомы устройства. Элементы SHALL различать источник. Связанная пара «альбом устройства → серверный альбом» SHALL отображаться одной карточкой альбома устройства с указателем связи и меткой режима; связанный серверный альбом SHALL NOT показываться в списке отдельной записью.
Scenario: Онлайн
- WHEN авторизованный пользователь открывает приложение
- THEN отображается список альбомов с обложками или плейсхолдером
Scenario: Офлайн из кэша
- WHEN сеть недоступна, но кэш существует
- THEN список альбомов отображается из кэша с признаком офлайн-режима
Scenario: Альбомы устройства
- WHEN у приложения есть доступ к медиа устройства
- THEN в списке появляются альбомы устройства наряду с серверными и помечены источником
Scenario: Связанная пара
- WHEN альбом устройства синхронизируется с серверным альбомом
- THEN в списке показывается одна карточка альбома устройства с указателем связи и меткой режима, а связанный серверный альбом отдельной записью не показывается
Requirement: Экран альбома устройства и настройки синхронизации
Приложение SHALL открывать альбом устройства с сеткой медиа и SHALL предоставлять настройки синхронизации этого альбома по свайпу вправо. Настройки SHALL содержать только выбор режима синхронизации.
Scenario: Открытие альбома устройства
- WHEN пользователь выбирает альбом устройства в списке
- THEN открывается сетка медиа этого альбома
Scenario: Настройки по свайпу
- WHEN пользователь свайпает вправо в открытом альбоме устройства
- THEN открываются настройки синхронизации с выбором режима и только им
Scenario: Метка перенесённого элемента
- WHEN оригинал элемента разгружен на сервер в режиме переноса
- THEN в сетке на элементе показывается значок облака
Scenario: Метка потерянного элемента
- WHEN серверной копии разгруженного элемента больше нет в целевом альбоме
- THEN в сетке на элементе показывается перечёркнутый значок облака
Requirement: Доступ к альбомам устройства
Приложение SHALL запрашивать доступ к медиа устройства, нужный для перечисления альбомов и чтения файлов, и SHALL работать без него, не показывая альбомы устройства.
Scenario: Доступ предоставлен
- WHEN пользователь предоставляет доступ к медиа устройства
- THEN приложение перечисляет альбомы устройства и их содержимое
Scenario: Доступ не предоставлен
- WHEN доступ к медиа устройства не предоставлен
- THEN приложение продолжает работать с серверными альбомами и не показывает альбомы устройства
Requirement: Постраничный просмотр альбома
Приложение SHALL показывать сетку медиа альбома с постраничной загрузкой по курсору и SHALL подгружать следующую страницу при достижении конца списка.
Scenario: Догрузка страницы
- WHEN пользователь прокручивает сетку до конца
- THEN приложение запрашивает следующую страницу по курсору и добавляет её к сетке
Scenario: Пустой альбом
- WHEN в альбоме нет медиа
- THEN отображается пустое состояние
Requirement: Просмотр медиа на весь экран
Полноэкранный просмотр SHALL поддерживать изображение с зумом пальцами, видео с постером и управлением воспроизведением, а также панораму 360; навигация между элементами альбома SHALL выполняться свайпом.
Scenario: Свайп между элементами
- WHEN пользователь свайпает в просмотре
- THEN показывается следующий или предыдущий элемент альбома без выхода из просмотра
Scenario: Видео
- WHEN открыт видеоэлемент
- THEN показывается постер и доступно воспроизведение с перемоткой
Requirement: Обновления в реальном времени
Пока экран альбома активен, приложение SHALL отображать изменения по SSE (новые, обновлённые и удалённые медиа, социальные события) и SHALL догонять пропущенное при переподключении.
Scenario: Новое фото с другого устройства
- WHEN другое устройство добавляет фото в открытый альбом
- THEN новое фото появляется в сетке без ручного обновления
Scenario: Переподключение
- WHEN SSE-соединение разорвалось и восстановилось
- THEN приложение дозагружает изменения, произошедшие за время разрыва
Requirement: Выбор медиа и альбома для загрузки
Приложение SHALL предоставлять выбор одного или нескольких фото и видео из системной галереи и SHALL требовать выбора альбома назначения перед постановкой в очередь.
Scenario: Постановка в очередь
- WHEN пользователь выбрал файлы и альбом назначения
- THEN задания загрузки ставятся в очередь и пользователь видит их статус
Scenario: Отказ сервера
- WHEN сервер отклоняет загрузку (например, из-за прав или размера)
- THEN задание помечается ошибкой с причиной от сервера
Requirement: Фоновая очередь загрузки
Загрузка SHALL выполняться по одному файлу за HTTP-запрос и SHALL продолжаться при уходе приложения из foreground, показывая прогресс в уведомлении; при ошибке SHALL выполняться повтор с нарастающей задержкой.
Scenario: Уход в фон
- WHEN приложение уходит в фон во время загрузки
- THEN загрузка продолжается и прогресс отображается в уведомлении
Scenario: Повтор при ошибке
- WHEN загрузка файла завершилась сетевой ошибкой
- THEN задание повторяется, а после исчерпания попыток помечается ошибкой
Requirement: Условия сети для загрузки
Приложение SHALL позволять ограничить загрузку сетью Wi-Fi; при ожидании подходящей сети задание остаётся в очереди и не выполняется.
Scenario: Только Wi-Fi
- WHEN ограничение «только Wi-Fi» включено, а доступна только сотовая сеть
- THEN загрузка не начинается до появления Wi-Fi, а задание остаётся в очереди
Requirement: Сохранность очереди между запусками
Очередь загрузки SHALL сохраняться на устройстве и SHALL продолжаться после перезапуска приложения или устройства.
Scenario: Возобновление после перезапуска
- WHEN приложение или устройство перезапускается при незавершённой очереди
- THEN незавершённые задания возобновляются
Requirement: Конвертация HEIC в JPEG
Файлы HEIC/HEIF SHALL конвертироваться на устройстве в JPEG перед загрузкой с сохранением даты съёмки и геолокации.
Scenario: Загрузка HEIC
- WHEN пользователь ставит в очередь HEIC-файл
- THEN загружается JPEG-версия, а дата съёмки и координаты из EXIF сохраняются
Scenario: Ошибка конвертации
- WHEN конвертация завершилась ошибкой
- THEN задание помечается ошибкой, повреждённый файл не загружается
Requirement: Кэш медиа по устойчивому ключу
Приложение SHALL кэшировать полученные превью и оригиналы по устойчивому идентификатору объекта, не зависящему от подписи и срока действия URL.
Scenario: Смена подписи
- WHEN URL одного и того же объекта со временем получает новую подпись
- THEN приложение переиспользует закэшированный объект вместо повторной загрузки
Scenario: Офлайн-отдача из кэша
- WHEN сеть недоступна, а объект есть в кэше
- THEN объект отображается из кэша
Requirement: Единый формат ошибок API
Приложение SHALL распознавать ошибки API формата {error:{code,message}} и SHALL
показывать пользователю понятное сообщение.
Scenario: Ошибка с кодом и сообщением
- WHEN сервер возвращает ошибку с
codeиmessage - THEN приложение показывает сообщение, при необходимости адаптированное под язык интерфейса
Requirement: Зум изображения жестами
Полноэкранный просмотр изображения SHALL поддерживать увеличение и уменьшение щипком (pinch), а при увеличенном изображении — панорамирование перетаскиванием.
Scenario: Щипок увеличивает изображение
- WHEN пользователь разводит пальцы на изображении
- THEN изображение увеличивается относительно вписанного вида
Scenario: Панорамирование при увеличении
- WHEN изображение увеличено, и пользователь перетаскивает его пальцем
- THEN видимая область изображения смещается, а границы изображения не отрываются от краёв области просмотра
Requirement: Двойной тап переключает вписанный вид и 100%
Двойной тап по изображению SHALL переключать вписанный вид и масштаб 100% натурального размера с якорем в точку нажатия.
Scenario: Вход в 100% из вписанного вида
- WHEN изображение показано вписанным, и пользователь делает двойной тап
- THEN изображение показывается в масштабе 100% натурального размера с центром в точке нажатия
Scenario: Возврат во вписанный вид
- WHEN изображение увеличено, и пользователь делает двойной тап
- THEN изображение возвращается во вписанный вид
Requirement: Предел зума по натуральному размеру
Зум изображения SHALL ограничиваться снизу вписанным видом, а сверху — 200% натурального размера изображения; при входе в зум SHALL догружаться оригинал изображения.
Scenario: Верхний предел
- WHEN пользователь продолжает увеличивать изображение за 200% натурального размера
- THEN масштаб останавливается на 200%, изображение не увеличивается дальше
Scenario: Оригинал при увеличении
- WHEN пользователь входит в зум
- THEN догружается оригинал изображения и подменяет превью по факту загрузки
Requirement: Навигация и сброс при зуме
Пока изображение увеличено, горизонтальный свайп SHALL NOT листать альбом, а жест 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 довосстанавливаться при следующей проверке (при запуске и при открытии альбома).
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 лист показывает локальные атрибуты и локальные действия элемента
Requirement: Живое обновление списка альбомов
Пока пользователь авторизован, приложение SHALL поддерживать персональный поток и применять события жизненного цикла альбома к локальному кэшу: создавать или заменять альбом по полученному объекту и удалять его по идентификатору, не выполняя дополнительный запрос списка.
Scenario: Альбом создан или изменён в другом месте
- WHEN в персональный поток приходит событие создания или изменения доступного альбома
- THEN альбом появляется в списке или заменяется без запроса списка
Scenario: Неизвестное событие
- WHEN в персональный поток приходит событие, не относящееся к жизненному циклу альбома
- THEN приложение не меняет локальный список
Scenario: Навигация между экранами
- WHEN пользователь переходит с главного экрана на другой экран приложения
- THEN подписка на персональный поток не пересоздаётся
Scenario: Выход из аккаунта
- WHEN пользователь выходит из аккаунта
- THEN подписка на персональный поток закрывается
Requirement: Догон списка при переподключении персонального потока
После восстановления персонального потока приложение SHALL приводить локальный список альбомов в соответствие с серверным снимком, чтобы отразить изменения, пропущенные за время разрыва соединения.
Scenario: Переподключение
- WHEN персональный поток восстановился после разрыва
- THEN приложение перезапрашивает список альбомов, удаляя из кэша альбомы, которых на сервере больше нет
Requirement: Потеря доступа к альбому
Приложение SHALL переставать отображать альбом, удалённый владельцем или ставший недоступным после исключения участника: альбом SHALL исчезать из локального кэша и списка, а экран открытого альбома SHALL возвращаться к списку.
Scenario: Альбом удалён во время просмотра
- WHEN владелец удаляет альбом, пока участник просматривает экран этого альбома
- THEN экран перестаёт показывать альбом и возвращается к списку
Scenario: Участник исключён
- WHEN участника исключают из альбома
- THEN альбом исчезает из его списка, а открытый экран возвращается к списку
Scenario: Экран альбома не открыт
- WHEN альбом удалён, а его экран не открыт
- THEN карточка альбома исчезает из списка
Scenario: Отсутствие альбома в кэше без сети
- WHEN приложение открывает экран альбома, которого нет в кэше, и сеть недоступна
- THEN экран не считается потерявшим доступ и не закрывается сам
Requirement: Выбор сортировки списка альбомов
Приложение SHALL предоставлять выбор порядка карточек в списке альбомов: «по времени изменения», «по названию» или «по числу фото», а также обратный порядок для выбранного варианта. Выбор SHALL сохраняться локально на устройстве и применяться при следующем запуске. Порядок SHALL применяться ко всему списку: карточки альбомов устройства и серверных альбомов упорядочиваются вместе.
Scenario: Выбор варианта
- WHEN пользователь выбирает вариант сортировки
- THEN карточки списка перестраиваются в соответствии с выбором
Scenario: Обратный порядок
- WHEN пользователь включает обратный порядок
- THEN выбранный вариант применяется в обратном направлении
Scenario: Альбомы устройства
- WHEN выбрана любая сортировка
- THEN карточки альбомов устройства упорядочиваются вместе с серверными, а для варианта «по времени изменения» используется дата самого свежего элемента альбома устройства
Scenario: Сортировка по умолчанию
- WHEN пользователь ещё не выбирал сортировку
- THEN карточки упорядочены по времени изменения, самые свежие сверху, обратный порядок выключен
Scenario: Сохранение выбора
- WHEN пользователь перезапускает приложение
- THEN список открывается с сохранёнными вариантом и направлением
Requirement: Действия потерявшего серверную копию превью
Шит потерявшего серверную копию элемента SHALL предлагать действие «Удалить с устройства» и SHALL NOT показывать серверные атрибуты и действия.
Scenario: Только удаление с устройства
- WHEN пользователь открывает атрибуты потерявшего серверную копию элемента
- THEN доступно действие «Удалить с устройства», а серверные действия отсутствуют
Requirement: Прогресс восстановления оригиналов
Пока идёт восстановление оригиналов, карточка альбома устройства SHALL показывать ход в третьей строке («Копии — восстановление <процент>%»), а экран альбома устройства SHALL показывать ход отдельной строкой. По завершении ход SHALL исчезать.
Scenario: Карточка в списке
- WHEN для альбома устройства идёт восстановление оригиналов
- THEN карточка показывает «<метка режима> — восстановление <процент>%»
Scenario: Экран альбома устройства
- WHEN для альбома устройства идёт восстановление оригиналов
- THEN экран альбома показывает ход восстановления
Scenario: Завершение
- WHEN восстановление оригиналов завершилось
- THEN ход больше не показывается, а карточка возвращается к метке режима