feat: Lightroom-style workspace UI #2
+10
@@ -37,3 +37,13 @@
|
|||||||
#### Scenario: Счётчики в ответе
|
#### Scenario: Счётчики в ответе
|
||||||
- **WHEN** клиент запрашивает список альбомов или альбом по id
|
- **WHEN** клиент запрашивает список альбомов или альбом по id
|
||||||
- **THEN** ответ содержит число фото и число участников альбома
|
- **THEN** ответ содержит число фото и число участников альбома
|
||||||
|
|
||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Удаление альбома
|
||||||
|
Владелец SHALL иметь возможность удалить альбом; фото альбома SHALL помещаться в корзину без
|
||||||
|
удаления объектов хранилища, а участники и share-ссылки SHALL удаляться вместе с альбомом.
|
||||||
|
|
||||||
|
#### Scenario: Удаление альбома
|
||||||
|
- **WHEN** владелец удаляет альбом
|
||||||
|
- **THEN** фото альбома попадают в корзину без привязки к альбому и файлы сохраняются, участники и share-ссылки удаляются
|
||||||
@@ -35,8 +35,47 @@
|
|||||||
- **THEN** система сохраняет изменения
|
- **THEN** система сохраняет изменения
|
||||||
|
|
||||||
### Requirement: Удаление альбома
|
### Requirement: Удаление альбома
|
||||||
Владелец SHALL иметь возможность удалить альбом вместе с содержимым.
|
Владелец SHALL иметь возможность удалить альбом; фото альбома SHALL помещаться в корзину без
|
||||||
|
удаления объектов хранилища, а участники и share-ссылки SHALL удаляться вместе с альбомом.
|
||||||
|
|
||||||
#### Scenario: Удаление альбома
|
#### Scenario: Удаление альбома
|
||||||
- **WHEN** владелец удаляет альбом
|
- **WHEN** владелец удаляет альбом
|
||||||
- **THEN** система удаляет альбом, его фото, участников и share-ссылки
|
- **THEN** фото альбома попадают в корзину без привязки к альбому и файлы сохраняются, участники и share-ссылки удаляются
|
||||||
|
|
||||||
|
### Requirement: Отображение обложки альбома
|
||||||
|
Данные альбома SHALL включать URL миниатюры обложки, когда обложка задана, чтобы клиенты
|
||||||
|
могли показать её в списке, рейле и карточке.
|
||||||
|
|
||||||
|
#### Scenario: Обложка задана
|
||||||
|
- **WHEN** клиент запрашивает список альбомов или альбом по id, и у альбома есть обложка
|
||||||
|
- **THEN** ответ содержит URL миниатюры обложки
|
||||||
|
|
||||||
|
#### Scenario: Обложка отсутствует
|
||||||
|
- **WHEN** у альбома нет обложки или фото обложки удалено
|
||||||
|
- **THEN** ответ не содержит URL обложки, и клиент показывает плейсхолдер
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Выбор обложки
|
||||||
|
Владелец и админ SHALL иметь возможность назначить обложкой любое фото альбома или сбросить
|
||||||
|
обложку; после сброса обложка определяется заново по умолчанию.
|
||||||
|
|
||||||
|
#### Scenario: Назначение обложки
|
||||||
|
- **WHEN** владелец выбирает фото альбома как обложку
|
||||||
|
- **THEN** система сохраняет выбор и отражает его в списке и карточках
|
||||||
|
|
||||||
|
#### Scenario: Сброс обложки
|
||||||
|
- **WHEN** админ сбрасывает обложку
|
||||||
|
- **THEN** система удаляет явный выбор, и обложка возвращается к значению по умолчанию
|
||||||
|
|
||||||
|
#### Scenario: Нет прав на смену обложки
|
||||||
|
- **WHEN** участник без права редактирования пытается сменить обложку
|
||||||
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Счётчики альбома
|
||||||
|
Данные альбома SHALL включать количество фото и участников, чтобы панель и карточки могли
|
||||||
|
показать их без отдельных запросов.
|
||||||
|
|
||||||
|
#### Scenario: Счётчики в ответе
|
||||||
|
- **WHEN** клиент запрашивает список альбомов или альбом по id
|
||||||
|
- **THEN** ответ содержит число фото и число участников альбома
|
||||||
|
|||||||
@@ -45,3 +45,24 @@
|
|||||||
#### Scenario: Выход
|
#### Scenario: Выход
|
||||||
- **WHEN** пользователь вызывает logout с действующим refresh-токеном
|
- **WHEN** пользователь вызывает logout с действующим refresh-токеном
|
||||||
- **THEN** система отзывает refresh-токен, и его дальнейшее использование отклоняется
|
- **THEN** система отзывает refresh-токен, и его дальнейшее использование отклоняется
|
||||||
|
|
||||||
|
### Requirement: Хранение пользовательских настроек интерфейса
|
||||||
|
Система SHALL хранить настройки отображения в профиле пользователя и SHALL возвращать их при
|
||||||
|
получении текущего пользователя. Настройки SHALL быть приватными для пользователя.
|
||||||
|
Отсутствие настроек SHALL трактоваться как значения по умолчанию.
|
||||||
|
|
||||||
|
#### Scenario: Получение настроек
|
||||||
|
- **WHEN** аутентифицированный пользователь запрашивает свой профиль
|
||||||
|
- **THEN** ответ содержит его настройки отображения (или пустой объект по умолчанию)
|
||||||
|
|
||||||
|
#### Scenario: Сохранение настроек
|
||||||
|
- **WHEN** пользователь сохраняет настройки отображения
|
||||||
|
- **THEN** система сохраняет их в профиле и возвращает сохранённое состояние
|
||||||
|
|
||||||
|
#### Scenario: Изоляция настроек
|
||||||
|
- **WHEN** другой пользователь запрашивает свой профиль
|
||||||
|
- **THEN** он не получает настройки первого пользователя
|
||||||
|
|
||||||
|
#### Scenario: Некорректные настройки
|
||||||
|
- **WHEN** пользователь присылает настройки недопустимой структуры или размера
|
||||||
|
- **THEN** система отклоняет запрос с ошибкой и не меняет сохранённые настройки
|
||||||
|
|||||||
@@ -55,3 +55,125 @@
|
|||||||
#### Scenario: Удаление чужого фото участником
|
#### Scenario: Удаление чужого фото участником
|
||||||
- **WHEN** участник с ролью member пытается удалить чужое фото
|
- **WHEN** участник с ролью member пытается удалить чужое фото
|
||||||
- **THEN** система отклоняет запрос
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
|
### Requirement: Обложка по умолчанию
|
||||||
|
При обработке загруженного фото система SHALL назначать его обложкой альбома только если
|
||||||
|
обложка ещё не задана.
|
||||||
|
|
||||||
|
#### Scenario: Первое фото
|
||||||
|
- **WHEN** фото обработано, и у альбома нет обложки
|
||||||
|
- **THEN** система назначает это фото обложкой
|
||||||
|
|
||||||
|
#### Scenario: Обложка уже задана
|
||||||
|
- **WHEN** фото обработано, а обложка уже задана
|
||||||
|
- **THEN** система не меняет обложку
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Переименование фото
|
||||||
|
Автор фото, владелец и админ альбома SHALL иметь возможность изменить имя файла фото;
|
||||||
|
остальные SHALL получать отказ, а пустое имя SHALL отклоняться.
|
||||||
|
|
||||||
|
#### Scenario: Переименование автором
|
||||||
|
- **WHEN** автор меняет имя файла своего фото на непустое
|
||||||
|
- **THEN** система сохраняет новое имя и транслирует изменение подписчикам альбома
|
||||||
|
|
||||||
|
#### Scenario: Пустое имя
|
||||||
|
- **WHEN** пользователь подтверждает пустое имя файла
|
||||||
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
|
#### Scenario: Нет прав
|
||||||
|
- **WHEN** участник без прав переименовывает чужое фото
|
||||||
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Ограничение размера загрузки
|
||||||
|
Система SHALL ограничивать размер загружаемых файлов и SHALL отвечать понятной ошибкой при
|
||||||
|
превышении лимита, а не ошибкой разбора формы.
|
||||||
|
|
||||||
|
#### Scenario: Превышение лимита
|
||||||
|
- **WHEN** загружаемый файл превышает максимальный размер
|
||||||
|
- **THEN** система отклоняет загрузку с явной ошибкой о превышении размера
|
||||||
|
|
||||||
|
#### Scenario: Файл в пределах лимита
|
||||||
|
- **WHEN** файл не превышает лимит
|
||||||
|
- **THEN** система принимает multipart-загрузку и обрабатывает фото
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Метаданные фото (EXIF)
|
||||||
|
При загрузке фото система SHALL извлекать распознаваемые EXIF-атрибуты и SHALL возвращать их
|
||||||
|
вместе с данными фото; при отсутствии метаданных SHALL возвращать пустой набор.
|
||||||
|
|
||||||
|
#### Scenario: Фото с метаданными
|
||||||
|
- **WHEN** загружается фото с EXIF
|
||||||
|
- **THEN** данные фото содержат извлечённые атрибуты (камера, экспозиция, ISO, дата съёмки и др.)
|
||||||
|
|
||||||
|
#### Scenario: Фото без метаданных
|
||||||
|
- **WHEN** загружается фото без читаемых EXIF
|
||||||
|
- **THEN** данные фото не содержат атрибутов, а загрузка выполняется успешно
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Перенос и копирование фото между альбомами
|
||||||
|
Пользователь с правом удаления в исходном альбоме и правом загрузки в целевом SHALL иметь
|
||||||
|
возможность перенести или скопировать фото в другой альбом. Операции SHALL изменять только
|
||||||
|
метаданные и SHALL не изменять объекты хранилища.
|
||||||
|
|
||||||
|
#### Scenario: Перенос
|
||||||
|
- **WHEN** пользователь переносит фото в другой альбом
|
||||||
|
- **THEN** фото исчезает из исходного альбома и появляется в целевом, объекты S3 не меняются
|
||||||
|
|
||||||
|
#### Scenario: Копирование
|
||||||
|
- **WHEN** пользователь копирует фото в другой альбом
|
||||||
|
- **THEN** в целевом альбоме появляется новая запись, ссылающаяся на те же объекты S3
|
||||||
|
|
||||||
|
|
||||||
|
### Requirement: Корзина фото
|
||||||
|
Удаление фото SHALL помещать его в корзину (мягкое удаление). Восстановление 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** показываются подходящие метки пользователя для выбора
|
||||||
|
|
||||||
|
#### Scenario: Снятие метки
|
||||||
|
- **WHEN** пользователь убирает метку с фото
|
||||||
|
- **THEN** метка отвязывается от фото
|
||||||
|
|||||||
@@ -0,0 +1,384 @@
|
|||||||
|
# ui-workspace Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Рабочий стол веб-приложения: постоянный каркас с рейлом альбомов, контекстной панелью,
|
||||||
|
режимом просмотра фото и адаптивным поведением, обеспечивающий цельный «lightroom»-вид.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Рабочий стол приложения
|
||||||
|
Аутентифицированные экраны SHALL отображаться внутри постоянного каркаса с топбаром, левым
|
||||||
|
рейлом альбомов и контекстной правой панелью. Публичные экраны (вход, инвайт, share-ссылка)
|
||||||
|
SHALL отображаться вне каркаса, но в общей теме оформления.
|
||||||
|
|
||||||
|
#### Scenario: Внутренний экран
|
||||||
|
- **WHEN** аутентифицированный пользователь открывает список альбомов или альбом
|
||||||
|
- **THEN** экран отрисован внутри каркаса с рейлом и панелью, рейл не перезагружается при переходе
|
||||||
|
|
||||||
|
#### Scenario: Публичный экран
|
||||||
|
- **WHEN** пользователь открывает публичную share-ссылку без входа
|
||||||
|
- **THEN** экран отрисован без рейла и контекстной панели, но в тех же цветовых токенах
|
||||||
|
|
||||||
|
### Requirement: Рейл альбомов
|
||||||
|
Рейл SHALL постоянно показывать список доступных альбомов с их обложками и отмечать
|
||||||
|
активный альбом.
|
||||||
|
|
||||||
|
#### Scenario: Активный альбом
|
||||||
|
- **WHEN** пользователь находится в альбоме
|
||||||
|
- **THEN** соответствующий элемент рейла выделен, остальные показывают обложки или плейсхолдер
|
||||||
|
|
||||||
|
### Requirement: Создание альбома
|
||||||
|
Создание альбома SHALL выполняться через иконочную кнопку с подсказкой, открывающую
|
||||||
|
модальное окно ввода названия, вместо инлайн-формы.
|
||||||
|
|
||||||
|
#### Scenario: Создание через модалку
|
||||||
|
- **WHEN** пользователь нажимает кнопку создания, вводит название и подтверждает
|
||||||
|
- **THEN** система создаёт альбом и делает его активным
|
||||||
|
|
||||||
|
#### Scenario: Пустое название
|
||||||
|
- **WHEN** пользователь подтверждает пустое название
|
||||||
|
- **THEN** создание не выполняется
|
||||||
|
|
||||||
|
### Requirement: Контекстная панель альбома
|
||||||
|
Правая панель SHALL показывать превью обложки, название, счётчики фото и участников,
|
||||||
|
управление обложкой и переходы к участникам, настройкам и ссылкам. Элементы управления
|
||||||
|
обложкой SHALL быть доступны только owner и admin.
|
||||||
|
|
||||||
|
#### Scenario: Владелец альбома
|
||||||
|
- **WHEN** owner открывает альбом
|
||||||
|
- **THEN** панель показывает управление обложкой и переходы к участникам и настройкам
|
||||||
|
|
||||||
|
#### Scenario: Наблюдатель
|
||||||
|
- **WHEN** viewer открывает альбом
|
||||||
|
- **THEN** панель не показывает управление обложкой
|
||||||
|
|
||||||
|
### Requirement: Режим просмотра фотографии
|
||||||
|
Просмотр фото SHALL быть отдельным маршрутом внутри каркаса с крупным изображением,
|
||||||
|
лентой миниатюр снизу и панелью метаданных и комментариев. Тот же режим SHALL
|
||||||
|
использоваться на публичных share-страницах.
|
||||||
|
|
||||||
|
#### Scenario: Открытие фото
|
||||||
|
- **WHEN** пользователь выбирает фото в сетке
|
||||||
|
- **THEN** открывается маршрут фото в каркасе, рейл и панель остаются доступны, адрес отражает фото
|
||||||
|
|
||||||
|
#### Scenario: Навигация в просмотре
|
||||||
|
- **WHEN** пользователь использует стрелки влево/вправо или ленту миниатюр
|
||||||
|
- **THEN** показывается соседнее фото, адрес обновляется
|
||||||
|
|
||||||
|
#### Scenario: Публичный просмотр
|
||||||
|
- **WHEN** посетитель share-ссылки открывает фото
|
||||||
|
- **THEN** используется тот же режим просмотра без рейла и панели
|
||||||
|
|
||||||
|
### Requirement: Плотность сетки
|
||||||
|
Сетка SHALL давать пользователю управлять размером миниатюр, и выбранный размер SHALL
|
||||||
|
сохраняться между сессиями.
|
||||||
|
|
||||||
|
#### Scenario: Изменение размера
|
||||||
|
- **WHEN** пользователь двигает регулятор плотности
|
||||||
|
- **THEN** размер миниатюр меняется, значение сохраняется и восстанавливается при следующем открытии
|
||||||
|
|
||||||
|
### Requirement: Загрузка фотографий из рабочего стола
|
||||||
|
Загрузка SHALL запускаться действием в тулбаре; перетаскивание файлов над альбомом SHALL
|
||||||
|
показывать оверлей и загружать их; пустой альбом SHALL показывать подсказку-зону загрузки.
|
||||||
|
Загрузка SHALL быть доступна только ролям с правом загрузки.
|
||||||
|
|
||||||
|
#### Scenario: Перетаскивание
|
||||||
|
- **WHEN** пользователь с правом загрузки перетаскивает файлы над альбомом
|
||||||
|
- **THEN** показывается оверлей загрузки, и файлы загружаются
|
||||||
|
|
||||||
|
#### Scenario: Пустой альбом
|
||||||
|
- **WHEN** пользователь открывает альбом без фото и имеет право загрузки
|
||||||
|
- **THEN** в центре показана зона-подсказка загрузки
|
||||||
|
|
||||||
|
### Requirement: Темы и графитовый хром
|
||||||
|
Тёмная тема SHALL использовать графитовый хром Lightroom и SHALL применяться по умолчанию;
|
||||||
|
нейтральная тема SHALL быть тёплым графитом; остальные темы SHALL оставаться доступными, а
|
||||||
|
скроллбары SHALL быть стилизованы в цвет темы.
|
||||||
|
|
||||||
|
#### Scenario: Первый вход
|
||||||
|
- **WHEN** пользователь впервые открывает приложение без сохранённой темы
|
||||||
|
- **THEN** применяется тёмная графитовая тема
|
||||||
|
|
||||||
|
#### Scenario: Смена темы
|
||||||
|
- **WHEN** пользователь выбирает другую тему
|
||||||
|
- **THEN** интерфейс, иконки и скроллбары меняются согласованно, и выбор сохраняется
|
||||||
|
|
||||||
|
#### Scenario: Нейтральная тема
|
||||||
|
- **WHEN** пользователь выбирает нейтральную тему
|
||||||
|
- **THEN** применяется тёплый графитовый хром, отличный от холодной тёмной темы
|
||||||
|
|
||||||
|
### Requirement: Адаптивность рабочего стола
|
||||||
|
На узких экранах рейл SHALL становиться выдвижной панелью, контекстная панель —
|
||||||
|
сворачиваемой секцией, а лента миниатюр — горизонтально прокручиваемой.
|
||||||
|
|
||||||
|
#### Scenario: Узкий экран
|
||||||
|
- **WHEN** ширина окна меньше порога рабочего стола
|
||||||
|
- **THEN** рейл скрыт за кнопкой открытия, панель сворачиваема, лента прокручивается горизонтально
|
||||||
|
|
||||||
|
### Requirement: Доступность рабочего стола
|
||||||
|
Иконочные органы управления каркаса SHALL иметь доступные имена, панели SHALL быть
|
||||||
|
достижимы с клавиатуры с видимым фокусом, анимации SHALL учитывать
|
||||||
|
предпочтение уменьшенного движения.
|
||||||
|
|
||||||
|
#### Scenario: Клавиатурная навигация
|
||||||
|
- **WHEN** пользователь работает только с клавиатуры
|
||||||
|
- **THEN** органы управления каркаса достижимы, доступные имена присутствуют, фокус виден
|
||||||
|
|
||||||
|
### Requirement: Изменение ширины панелей
|
||||||
|
Пользователь SHALL иметь возможность менять ширину левой и правой панелей перетаскиванием, а
|
||||||
|
выбранная ширина SHALL сохраняться между сессиями.
|
||||||
|
|
||||||
|
#### Scenario: Перетаскивание разделителя
|
||||||
|
- **WHEN** пользователь тянет разделитель у панели на рабочем столе
|
||||||
|
- **THEN** панель меняет ширину в допустимых пределах
|
||||||
|
|
||||||
|
#### Scenario: Сохранение ширины
|
||||||
|
- **WHEN** пользователь перезагружает приложение
|
||||||
|
- **THEN** восстановленные панели имеют сохранённую ширину
|
||||||
|
|
||||||
|
### Requirement: Сворачиваемые разделы панели
|
||||||
|
Контекстная панель SHALL группировать содержимое в сворачиваемые разделы, а состояние
|
||||||
|
сворачивания SHALL сохраняться; раздел «Информация» SHALL показывать метаданные фото,
|
||||||
|
включая извлечённые EXIF-атрибуты.
|
||||||
|
|
||||||
|
#### Scenario: Сворачивание раздела
|
||||||
|
- **WHEN** пользователь нажимает заголовок раздела
|
||||||
|
- **THEN** содержимое раздела скрывается или показывается, состояние сохраняется
|
||||||
|
|
||||||
|
#### Scenario: Метаданные фото
|
||||||
|
- **WHEN** открыт просмотр фото
|
||||||
|
- **THEN** раздел «Информация» показывает размер, тип, разрешение, дату съёмки, координаты и извлечённые EXIF-атрибуты
|
||||||
|
|
||||||
|
### Requirement: Полноэкранный просмотр фотографии
|
||||||
|
В режиме просмотра SHALL быть доступен переход в полноэкранный режим кнопкой и хоткеем `f`.
|
||||||
|
В полноэкранном режиме верхняя и нижняя панели SHALL скрываться и показываться у
|
||||||
|
соответствующей кромки экрана.
|
||||||
|
|
||||||
|
#### Scenario: Вход в полный экран
|
||||||
|
- **WHEN** пользователь нажимает кнопку полного экрана или клавишу `f`
|
||||||
|
- **THEN** просмотр разворачивается на весь экран, панели скрыты
|
||||||
|
|
||||||
|
#### Scenario: Панель по кромке
|
||||||
|
- **WHEN** курсор касается верхней или нижней кромки экрана
|
||||||
|
- **THEN** соответствующая панель показывается, а при уходе курсора скрывается сразу
|
||||||
|
|
||||||
|
#### Scenario: Выход из полного экрана
|
||||||
|
- **WHEN** пользователь повторно нажимает кнопку или клавишу `f`
|
||||||
|
- **THEN** полноэкранный режим закрывается
|
||||||
|
|
||||||
|
#### Scenario: Полноэкранный режим приложения
|
||||||
|
- **WHEN** включён полноэкранный режим приложения, и пользователь нажимает `f`
|
||||||
|
- **THEN** открывается полноэкранный просмотр фото (вложенно), а полноэкранный режим приложения не выключается
|
||||||
|
|
||||||
|
### Requirement: Зум в просмотре
|
||||||
|
Просмотр SHALL поддерживать зум колесом мыши без прокрутки, с привязкой к указателю и
|
||||||
|
верхним пределом 200% размеров фото. `Space` SHALL возвращать изображение из любого зума во
|
||||||
|
вписанный вид, а из вписанного — в 100%. При зуме SHALL догружаться оригинал изображения.
|
||||||
|
Стрелки соседних фото SHALL появляться у левой/правой кромки и прятаться в зуме. Зум SHALL
|
||||||
|
работать и в полноэкранном режиме.
|
||||||
|
|
||||||
|
#### Scenario: Зум колесом к указателю
|
||||||
|
- **WHEN** пользователь вращает колесо мыши над фото
|
||||||
|
- **THEN** масштаб меняется относительно курсора, страница не прокручивается, предел — 200%
|
||||||
|
|
||||||
|
#### Scenario: Пробел
|
||||||
|
- **WHEN** пользователь нажимает `Space`
|
||||||
|
- **THEN** из вписанного вида изображение переходит в 100%, а из любого зума возвращается во вписанный
|
||||||
|
|
||||||
|
#### Scenario: Оригинал в зуме
|
||||||
|
- **WHEN** пользователь входит в зум
|
||||||
|
- **THEN** догружается оригинал изображения и подменяется по факту загрузки
|
||||||
|
|
||||||
|
#### Scenario: Стрелки соседних фото
|
||||||
|
- **WHEN** курсор находится у левой или правой кромки области просмотра
|
||||||
|
- **THEN** показывается соответствующая стрелка, скрываясь сразу после ухода; в зуме стрелки скрыты
|
||||||
|
|
||||||
|
#### Scenario: Панорамирование
|
||||||
|
- **WHEN** фото увеличено
|
||||||
|
- **THEN** пользователь может перемещать изображение перетаскиванием и прокруткой
|
||||||
|
|
||||||
|
### Requirement: Удаление фото из просмотра
|
||||||
|
Автор фото, владелец и админ альбома SHALL иметь возможность удалить текущее фото из режима
|
||||||
|
просмотра; удаление SHALL подтверждаться диалогом.
|
||||||
|
|
||||||
|
#### Scenario: Подтверждение удаления
|
||||||
|
- **WHEN** пользователь с правом удаления нажимает «Удалить»
|
||||||
|
- **THEN** открывается диалог подтверждения, и после подтверждения фото удаляется
|
||||||
|
|
||||||
|
#### Scenario: Лента после удаления
|
||||||
|
- **WHEN** фото удалено
|
||||||
|
- **THEN** просмотр переходит к соседнему фото, а лента миниатюр обновляется без удалённого
|
||||||
|
|
||||||
|
### Requirement: Возврат к обзору
|
||||||
|
Из альбома и из режима просмотра SHALL быть доступен возврат к обзору альбомов.
|
||||||
|
|
||||||
|
#### Scenario: Возврат из альбома
|
||||||
|
- **WHEN** пользователь нажимает кнопку «назад» слева от названия альбома
|
||||||
|
- **THEN** открывается обзор альбомов
|
||||||
|
|
||||||
|
#### Scenario: Возврат из просмотра
|
||||||
|
- **WHEN** пользователь нажимает кнопку «назад» в режиме просмотра
|
||||||
|
- **THEN** открывается альбом с сеткой фото
|
||||||
|
|
||||||
|
### Requirement: Настройки списка атрибутов информации
|
||||||
|
Раздел «Информация» SHALL предоставлять доступ к настройкам (иконка-шестерёнка), открывающим
|
||||||
|
модальное окно со списком EXIF-атрибутов, где пользователь SHALL отмечать отображаемые
|
||||||
|
атрибуты и задавать их подписи. В окне SHALL быть доступны действия «отметить все» и
|
||||||
|
«снять все». Настройки SHALL применяться ко всем фото и SHALL сохраняться в профиле
|
||||||
|
пользователя. При отсутствии сохранённых настроек SHALL отображаться базовый набор атрибутов
|
||||||
|
(камера, объектив, выдержка, диафрагма, ISO, фокусное расстояние).
|
||||||
|
|
||||||
|
#### Scenario: Открытие настроек
|
||||||
|
- **WHEN** пользователь нажимает иконку настроек в разделе «Информация»
|
||||||
|
- **THEN** открывается модальное окно со списком EXIF-атрибутов: галочки видимости и поля подписей, а также действия «отметить все»/«снять все»
|
||||||
|
|
||||||
|
#### Scenario: Значения по умолчанию
|
||||||
|
- **WHEN** у пользователя нет сохранённых настроек
|
||||||
|
- **THEN** в разделе «Информация» показан базовый набор атрибутов, а остальные доступны по элементу «…»
|
||||||
|
|
||||||
|
#### Scenario: Сохранение настроек
|
||||||
|
- **WHEN** пользователь отмечает атрибуты, задаёт подпись и сохраняет
|
||||||
|
- **THEN** раздел «Информация» учитывает изменения, а настройки сохраняются в профиле
|
||||||
|
|
||||||
|
#### Scenario: Сброс настроек
|
||||||
|
- **WHEN** пользователь сбрасывает настройки
|
||||||
|
- **THEN** сохранённые настройки удаляются из профиля, и отображается базовый набор с исходными подписями
|
||||||
|
|
||||||
|
### Requirement: Свёртка скрытых атрибутов
|
||||||
|
Если настройками часть атрибутов скрыта, в конце списка атрибутов SHALL отображаться элемент
|
||||||
|
«…»; нажатие на него 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 выбирать несколько фото: обычный клик — одно фото,
|
||||||
|
Ctrl/Cmd-клик — добавить или убрать, Shift-клик — диапазон. Выбранные фото SHALL быть отмечены.
|
||||||
|
|
||||||
|
#### Scenario: Мультивыбор
|
||||||
|
- **WHEN** пользователь кликает по фото с зажатым Ctrl/Cmd или Shift
|
||||||
|
- **THEN** соответствующие фото отмечены, а панель показывает количество выбранных
|
||||||
|
|
||||||
|
### Requirement: Действия с выбранными фото
|
||||||
|
Когда выбрано одно или несколько фото, правая панель SHALL показывать раздел «Действия» со
|
||||||
|
строками-пунктами (иконка + подпись) «Открыть (просмотр)», «Переместить», «Копировать» и
|
||||||
|
«Удалить»; удаление SHALL подтверждаться диалогом.
|
||||||
|
|
||||||
|
#### Scenario: Действия
|
||||||
|
- **WHEN** выбрано одно или несколько фото
|
||||||
|
- **THEN** панель показывает раздел «Действия» с пунктами «Открыть (просмотр)», «Переместить», «Копировать» и «Удалить»
|
||||||
|
|
||||||
|
### Requirement: Перетаскивание выбранных фото на альбом
|
||||||
|
Выбранные фото SHALL перетаскиваться на альбом в рейле; при отпускании SHALL открываться
|
||||||
|
диалог выбора переноса или копирования с указанием целевого альбома. Во время такого
|
||||||
|
перетаскивания зона загрузки файлов SHALL не показываться.
|
||||||
|
|
||||||
|
#### Scenario: Перетаскивание на альбом
|
||||||
|
- **WHEN** пользователь перетаскивает выделенные фото на альбом в рейле и отпускает
|
||||||
|
- **THEN** открывается диалог с выбором переноса/копирования и целевым альбомом
|
||||||
|
|
||||||
|
### Requirement: Корзина в списке альбомов
|
||||||
|
Рейл альбомов SHALL содержать вход в корзину последним элементом списка (с иконкой корзины).
|
||||||
|
Экран обзора альбомов SHALL не показывать пустую правую панель.
|
||||||
|
|
||||||
|
#### Scenario: Вход в корзину
|
||||||
|
- **WHEN** пользователь открывает приложение
|
||||||
|
- **THEN** в левом рейле последним элементом списка показана «Корзина» с иконкой корзины
|
||||||
|
|
||||||
|
#### Scenario: Обзор без панели
|
||||||
|
- **WHEN** пользователь открывает обзор альбомов
|
||||||
|
- **THEN** правая панель не отображается
|
||||||
|
|
||||||
|
### Requirement: Действия в режиме просмотра
|
||||||
|
В режиме просмотра правая панель 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** альбом удаляется, а его фото попадают в корзину
|
||||||
|
|
||||||
|
### Requirement: Счётчики в рейле
|
||||||
|
Рейл SHALL показывать число фото у каждого альбома и число элементов в корзине.
|
||||||
|
|
||||||
|
#### Scenario: Счётчики
|
||||||
|
- **WHEN** пользователь смотрит на рейл альбомов
|
||||||
|
- **THEN** у каждого альбома показано число фото, а у корзины — число удалённых фото
|
||||||
|
|
||||||
|
### Requirement: Метки в панели фото
|
||||||
|
Панель фото SHALL содержать раздел «Метки» с чипами меток фото и полем добавления, дающим
|
||||||
|
поиск по меткам пользователя и создание новых.
|
||||||
|
|
||||||
|
#### Scenario: Раздел «Метки»
|
||||||
|
- **WHEN** открыт просмотр или выбран один фото в сетке
|
||||||
|
- **THEN** в панели есть раздел «Метки» с текущими метками и полем добавления с поиском
|
||||||
|
|
||||||
|
### Requirement: Компактный верхний хром
|
||||||
|
Верхняя панель приложения и верхняя панель режима просмотра SHALL иметь минимальную высоту
|
||||||
|
(узкие отступы, иконочные органы управления), сохраняя все действия доступными. Верхняя панель
|
||||||
|
режима просмотра SHALL быть прозрачным оверлеем и SHALL не занимать место в раскладке,
|
||||||
|
увеличивая область фото.
|
||||||
|
|
||||||
|
#### Scenario: Компактные верхние панели
|
||||||
|
- **WHEN** открыт список альбомов или режим просмотра фото
|
||||||
|
- **THEN** верхняя панель занимает минимум высоты, а её действия (навигация, полный экран, скачивание, удаление) доступны
|
||||||
|
|
||||||
|
#### Scenario: Прозрачная панель просмотра
|
||||||
|
- **WHEN** открыт режим просмотра фото
|
||||||
|
- **THEN** верхняя панель нарисована поверх фото без фона и не уменьшает область изображения
|
||||||
Reference in New Issue
Block a user