116 lines
11 KiB
Markdown
116 lines
11 KiB
Markdown
# Diff: Уведомления (Notifications) — итерация 1 (2026-07-13)
|
||
|
||
Ff_app: **63.6%** (done 14 / open 8, n-a 1) · Fd_app: **20.0%** (Д done 2 / open 8; Roborazzi-эталон снят, веб-сверка ленты pending) · автор `b-mob-notify`
|
||
|
||
> **Итерация 1b (2026-07-13):** P1-лента закрыта лидом (`a30627a`) + P1-push unregister закрыт
|
||
> (клиент `cc7ad71` + вызов в logout `255c962`). Ff 45.5% → 63.6%.
|
||
|
||
> Сверка веб (`nextcloud/notifications 5.0.0-dev.0` + тема forbion, mail/078) ↔ **натив
|
||
> (реализован в app-shell)**. Лента УЖЕ работает: `NotificationsSheet` (`app/AppSheets.kt`) +
|
||
> `F7NotificationRow` (`core/designsystem`) + `NotificationsRepository` (`core/network`, API v2).
|
||
> `[done]` = есть в коде натива; `Fd=0%` — вёрстка на устройстве/визуально ещё не сверялась.
|
||
> Карта-источник: [`notifications.md`](notifications.md) (из кода + живая сверка forbion,
|
||
> Browser 1/`cloude`, read-only; лента `cloude` = 3 уведомления `firstrunwizard`).
|
||
>
|
||
> **NB зона:** лента в `app/AppSheets.kt` + `core/*` (зона лида) — P1-функционал он закрыл сам
|
||
> (mail/113). Моё: core/push (retry+unregister — done) и **Fd (Roborazzi-строка уведомления в
|
||
> `core/designsystem/src/test` + веб-эталон 360 CSS-px)** — по разрешению лида (mail/112б).
|
||
> `feature/notifications` — после приёмочного гейта (mail/112б).
|
||
|
||
Метки: `[Ф|Д]` (функционал/дизайн) · `[open|done|n-a]`.
|
||
|
||
---
|
||
|
||
## Экран 1. Триггер (колокольчик) — Ff n-a (зона лида)
|
||
Колокольчик-вход живёт в шелле (нижняя шторка, слот `#mobile-header-notifications`) — **зона
|
||
`b-dev-mobile`** (shell.md), не считаю в свой Ff.
|
||
**Ф (1, n-a 1):**
|
||
- [Ф][n-a] иконка-триггер + раскрытие ленты — шелл (лид). Индикатор непрочитанных (точка
|
||
`showDot` / warning `hasThrottledPushNotifications`) — если понадобится, отдельным пингом лиду.
|
||
|
||
## Экран 2. Лента (дропдаун/шит) — Ff 71.4% · Fd 0%
|
||
**Ф (8, done 5, open 2, n-a 1):**
|
||
- [Ф][done] загрузка списка (`NotificationsRepository.load`, OCS API v2, `limit=50`)
|
||
- [Ф][done] пустое состояние «Нет уведомлений» (иконка `nof-not-icon.svg` + текст) — `items.isEmpty()`
|
||
- [Ф][done] состояние загрузки (спиннер `CircularProgressIndicator`)
|
||
- [Ф][done] состояние ошибки (текст `error`)
|
||
- [Ф][done] **«Скрыть все уведомления»** (`dismissAll()` → `DELETE …/api/v2/notifications`) —
|
||
лид `a30627a` (заголовок ленты + кнопка + оптимистичное скрытие)
|
||
- [Ф][open] баннер fairUsePolicy при throttled push («Push notifications might be unreliable») — P3
|
||
- [Ф][open] авто-обновление ленты: сейчас только push-триггер (`refreshRequest`), ETag/поллинга
|
||
(`lastETag`/notify_push) НЕТ — P2
|
||
- [Ф][n-a] пустой вариант «Запрос разрешений браузера» (`webNotificationsGranted===null`) — n-a:
|
||
веб-концепт web-push; натив на FCM, разрешение POST_NOTIFICATIONS запрашивается системно
|
||
|
||
**Д (5, open 5):** [Д][open] вёрстка ленты по теме/токенам · [Д][open] высота/скролл шита ·
|
||
[Д][open] пустое состояние (вид иконки/текста) · [Д][open] состояние загрузки/ошибки ·
|
||
[Д][open] анимация inbox-zero (галочка+конфетти при переходе >0→0) — P3
|
||
|
||
## Экран 3. Элемент уведомления (`F7NotificationRow` ↔ `NotificationItem`) — Ff 58.3% · Fd 0%
|
||
**Ф (12, done 7, open 5):**
|
||
- [Ф][done] относительное время (`formatNotificationRelativeTime`) — совпадает с forbion («N минут назад»)
|
||
- [Ф][done] кнопка «Скрыть» (× → `dismissNotification` → `DELETE …/notifications/{id}`)
|
||
- [Ф][done] иконка app (`resolveNotificationIcon` + `AsyncImage` с auth-хедером)
|
||
- [Ф][done] subject (плоский текст)
|
||
- [Ф][done] message (плоский текст, если есть)
|
||
- [Ф][done] переход по тапу (`onNotificationClick` → `openAppLink(notification.link)`)
|
||
- [Ф][done] **action-кнопки уведомления** (`actions[]` → `F7NotificationActionUi`, FlowRow) —
|
||
лид `a30627a` (primary=заливка, прочие=контур); закрывает Talk-приглашения и т.п.
|
||
- [Ф][open] `subjectRich` (`NcRichText` + User/File-параметры) — только плоский subject — P2
|
||
- [Ф][open] `messageRich` (rich + autolink) — только плоский message — P2
|
||
- [Ф][open] `externalLink` (вариант «↗», target=_blank + primary-кнопка «Contact…») — не отличается
|
||
от обычной ссылки — P3
|
||
- [Ф][open] сворачивание длинного message (`.collapsed` + разворот по тапу) — нет — P3
|
||
- [Ф][open] подсветка нового `notification--new` — нет — P3
|
||
|
||
**Д (5, done 2, open 3):** нативный Roborazzi-эталон снят (`core/designsystem/src/test` →
|
||
`notification-row-states.png`, w360dp, перезаписан `8072539` после фикса лида).
|
||
> **Веб-эталон 360 CSS-px — техническое ограничение:** лента уведомлений НЕ рендерится в
|
||
> same-origin iframe (приложение `notifications` координирует вкладки — `setCurrentTabAsActive`,
|
||
> фетчит только «активная» вкладка; iframe как вторая вкладка остаётся пустым, хотя OCS API
|
||
> отдаёт 3 уведомления `firstrunwizard`). Populated-строки живьём для попиксельной сверки пока
|
||
> недоступны через iframe. Обходы на изучении; часть Д закрыта по Roborazzi-эталону + карте.
|
||
- [Д][done] **перенос текста primary-кнопки посреди слова** — было «Присоединитьс/я» на w360dp;
|
||
лид `bfa870c` (подпись действия 1.5× вместо 2×, maxLines=2 по словам, паддинги 16/9).
|
||
Верифицировано перезаписью Roborazzi: «Присоединиться» в одну строку. Находка Roborazzi.
|
||
- [Д][done] зазор subject↔message (сливались на 360dp) — лид `bfa870c` (6→10dp), подтверждено на PNG.
|
||
- [Д][open] компоновка строки (время+× сверху, иконка+subject/message) — сверить с веб-эталоном.
|
||
- [Д][open] вёрстка по теме (карточный стиль `_mobile-common.css` + токены) — vs веб-эталон.
|
||
- [Д][open] типографика: натив рендерит удвоенным кеглем (`.doubled()`) — сверить с мобильной темой.
|
||
|
||
## Экран 4. Кнопка действия (`F7NotificationActionUi` ↔ `ActionButton`) — Ff 66.7% · Fd 0%
|
||
Реализовано лидом (`a30627a`): парсинг `actions[]` (`parseActions`, type→uppercase, default GET,
|
||
primary), рендер `F7NotificationActionUi`, выполнение `executeAction`.
|
||
**Ф (3, done 2, open 1):**
|
||
- [Ф][done] primary/контур по флагу `primary` (`F7NotificationActionUi.primary`) — рендер FlowRow.
|
||
(нюанс упстрима: там `isWebLink||primary`→primary; в нативе только флаг `primary` — визуально
|
||
сойдётся, разберём в Fd, не Ф-дыра)
|
||
- [Ф][done] выполнение действия (`executeAction`: POST/PUT/DELETE, иначе GET, по абсолютному
|
||
`action.link` + `OCS-APIRequest`) + оптимистичное скрытие уведомления после
|
||
- [Ф][open] **WEB-действие как прямая ссылка/открытие в браузере** — `executeAction` для типа
|
||
`WEB` уходит в `else→GET` (упстрим: WEB = открыть `link` в браузере, а не HTTP-GET). Пограничный
|
||
случай, но семантика иная — P3. (сообщу лиду, если встретится WEB-action живьём)
|
||
|
||
---
|
||
|
||
## Вне карты-экрана: core/push (моя зона, отдельный бэклог)
|
||
Не входит в Ff ленты (нет веб-экрана-аналога), но моя зона и уже зафиксировано в представлении
|
||
(mail/070). Держу как отдельный трек:
|
||
- [Ф][done] **unregister при logout** — ЗАКРЫТО. Контракт f7push (mail/110). Клиент
|
||
`F7PushRegistrar.unregisterBlocking` (`cc7ad71`, compile+detekt green) + вызов в
|
||
`MainViewModel.logout()` best-effort на IO рядом с ревокацией (лид `255c962`, mail/112а). P1-push.
|
||
- [Ф][done] retry/бэкофф в `F7PushRegistrar.registerBlocking` (3 попытки, бэкофф 1с/3с, повтор
|
||
на 0/5xx/408/429, стоп на 2xx/4xx) — коммит `a6bda89`, compile+detekt green (P2-push)
|
||
- [Ф][n-a] серверные хвосты FCM (чистка 403 SenderId mismatch, старые `f7cloud-apk`) — ячейка A,
|
||
через integrator-b (mail/064) — вне натива
|
||
|
||
## Сводка
|
||
- **Ff = 63.6%** (done 14 / open 8; n-a 3 не в счёте: web-permission-empty, триггер-шелл, серверный FCM).
|
||
- **P1 — ЗАКРЫТ:** «Скрыть все» + action-кнопки + парсинг `actions` (лид `a30627a`);
|
||
unregister-push (клиент `cc7ad71` + вызов `255c962`); retry регистрации (`a6bda89`).
|
||
- **P2 (осталось):** rich subject/message, авто-обновление ETag.
|
||
- **P3 (осталось):** fairUsePolicy-баннер, external-«↗», WEB-action как ссылка, сворачивание
|
||
message, `notification--new`, inbox-zero.
|
||
- **Fd=0% → в работе автономно:** Roborazzi-скрин `F7NotificationRow` в `core/designsystem/src/test`
|
||
(w360dp) + веб-эталон 360 CSS-px (пустое состояние, без данных `cloude`) — по mail/111/112б.
|