5 Commits

Author SHA1 Message Date
glb_adm 557d2f0864 fix(камера): не держать превью-камеру весь звонок (лампочка горела при выкл. видео)
Первопричина: LocalVideoControlButton/LocalAudioControlButton на mounted() подписываются на
useDevices и держат подписку весь звонок; initializeDevices безусловно грабит камеру
(getUserMedia video:true) для превью, хотя кнопкам нужен лишь список устройств. Камера отпускалась
только по завершении звонка → индикатор горел при выключенном видео (медиа-конвейер звонка свой трек
останавливает корректно, но превью-подсистема — нет).

Фикс: разделены подписка на СПИСОК устройств и на ЖИВОЙ превью-поток. streamSubscribersCount +
единая точка контроля в updateAudio/VideoStream (без превью-подписчика поток не грабится и
останавливается — защищает и от watch). Кнопки звонка: requestStream:false. Диалог настроек —
без изменений (превью работает). enableDeviceEvents использует enumerateDevices (без камеры).

Сборка OK. НЕ деплоено — ждёт тест-фазу (docs/f7-fixes/camera-led-on-with-video-off.md).
2026-07-08 08:20:19 +00:00
glb_adm 49dd055a58 build: полная сборка в git — серверные PHP-зависимости lib/Vendor (438 файлов, из пиннированного релиза v22.0.12)
Type checking / changes (push) Has been cancelled
Type checking / test (push) Has been cancelled
Type checking / typescript-summary (push) Has been cancelled
Node tests / changes (push) Has been cancelled
Node tests / test (push) Has been cancelled
Node tests / test-summary (push) Has been cancelled
Теперь master f7_talk = ПОЛНЫЙ деплой-артефакт: built js (наша сборка) + lib/Vendor (серверные
PHP-deps) + патч Listener + version 22.0.12.1. Готов к брендингу dev-f7 и подписи dev-appstore.
Апстрим-подписи (appinfo/signature.json) в репо нет — переподпишет dev-appstore при публикации.
2026-07-06 22:20:16 +00:00
glb_adm 9dad445d11 build-release.sh: сборка полного деплой-артефакта (фронт npm + серверный vendor + патч + версия, минус брендинг/подпись)
Type checking / changes (push) Has been cancelled
Type checking / test (push) Has been cancelled
Type checking / typescript-summary (push) Has been cancelled
Node tests / changes (push) Has been cancelled
Node tests / test (push) Has been cancelled
Node tests / test-summary (push) Has been cancelled
Проверено: артефакт 37МБ собирается — js(наши)+lib/Vendor(vendor: CuyZ/Firebase/Psr)+Listener-патч+
version 22.0.12.1, apstream-подпись снята. Пробел: PHP/Composer для смены PHP-зависимостей (nd3 без PHP —
пока vendor из пиннированного релиза, детерминированно). Внешние входы: брендинг dev-f7, подпись dev-appstore, тест-стенд.
2026-07-06 22:15:51 +00:00
glb_adm e026bcbaa5 release 22.0.12-f7.1: ядро-паритет с glb
Type checking / changes (push) Has been cancelled
Type checking / test (push) Has been cancelled
Type checking / typescript-summary (push) Has been cancelled
Node tests / changes (push) Has been cancelled
Node tests / test (push) Has been cancelled
Node tests / test-summary (push) Has been cancelled
- Listener.php: форс ru для push больших звонков (единственная функц. правка ядра на glb),
  инкорпорирован в форк с пометкой о конфликте с З5 (мультиязычность) → вынести в config с dev-f7.
- appinfo version 22.0.12.1 (= f7.1; NC требует числовую версию).
- F7-PARITY.md: полный разбор слоёв (ядро=наше / брендинг=dev-f7 downstream), рецепт сборки glb-артефакта.
Брендинг (l10n/img/css/namespace/строки) НЕ в форке — зона dev-f7, применяется downstream.
2026-07-06 16:44:43 +00:00
glb_adm 2e3eaad31f docs: BUILD-f7.md — сборочная среда (Node 22.17), воспроизводимость подтверждена (55/65 бандлов = офиц. релиз), разбор downstream-правок glb (брендинг dev-f7 + патч Listener.php) 2026-07-06 14:18:33 +00:00
552 changed files with 25237 additions and 57 deletions
+1 -39
View File
@@ -1,39 +1 @@
# Exclude npm stuff /node_modules/
/build
/node_modules
# PHP Code Sniffer
/vendor
/vendor-bin/*/vendor
/lib/Vendor
/.php-cs-fixer.cache
# Local docs
/site
# Karma/jasmine coverage data
/coverage
/tests/php/coverage-html
/tests/php/clover.xml
/tests/php/.phpunit.result.cache
/tests/integration/vendor
/tests/integration/output
/drone
/findings.sarif
# PHP Dev server output (integration tests)
/tests/integration/phpserver*.log
# Compiled frontend assets
/css
/js
# VScode settings
/.vscode
*.code-workspace
# JetBrains IDEs settings
/.idea
# JetBrains Fleet settings
/.fleet
+37
View File
@@ -0,0 +1,37 @@
# Сборка форка f7_talk (Nextcloud Talk / spreed)
Форк ветки nextcloud/spreed. Базовый апстрим — **v22.0.12** (тег `v22.0.12-upstream`),
совместим с NC 32.0.5 (glb, forbion). Обновления с официальной ветки НЕ берём (решение владельца
2026-07-06) — источник версии Talk теперь этот репозиторий.
## Сборочная среда (проверено на nd3, 2026-07-06)
- Node **22.17.0** + npm **10.9.2** (package.json engines: node ^22, npm ^10.5). На nd3 ставится
в userspace: `/home/foradmin/f7-build/node-v22.17.0-linux-x64` (не системный).
- Зависимости фронтенда: `npm ci` по `package-lock.json` (воспроизводимо).
- Сборка: `NODE_OPTIONS=--max-old-space-size=8192 npm run build` (rspack, production) → каталог `js/`.
На 16 vCPU / 20 ГБ занимает ~20 с; 4 warning'а (olm.wasm __dirname/__filename) — безвредны.
## Воспроизводимость (подтверждена)
Наша сборка из исходников v22.0.12 сверена с ОФИЦИАЛЬНЫМ релизным артефактом
`nextcloud-releases/spreed v22.0.12`:
- **55 из 65** `.js`-бандлов — байт-в-байт идентичны.
- Расхождения: 10 файлов = `.map` (source maps, не грузятся клиентом) + `talk-collections.js`,
где отличается ТОЛЬКО порядок двух minifier-переменных (`p`/`d`) — недетерминизм минификатора,
функционально эквивалентно. Вывод: собранный нами Talk = официальному 22.0.12.
## Что на боевом glb отличается от стока (правки downstream, НЕ наши в форке)
Установленный на glb spreed = сток 22.0.12 + преобразования f7-брендинга (владелец — dev-f7,
их generalize/theme-конвейер), а НЕ ручной патч ядра:
- `l10n/*` (110 файлов): строки Nextcloud→F7cloud, ссылки docs;
- `img/*` (27): фавиконки/иконки бренда; `css/talk-main.css`: одна @media-правка;
- `js/*` (7 бандлов): namespace `http://nextcloud.com/ns``https://f7cloud.ru/ns` + бренд-строки;
- **единственный функциональный патч PHP**: `lib/Notification/Listener.php` — форс языка `ru`
для push-уведомлений больших звонков (упрощение: fallbackLang='ru', userLanguages=[]).
Вывод для форка: брендинг остаётся ПОСТ-сборочным шагом dev-f7 (их зона), либо переносится в форк
отдельным коммитом по согласованию. Патч Listener.php логично инкорпорировать в форк как наш.
## Релизы форка
Версии `22.0.12-f7.N`. Пайплайн: изменение → `npm ci && npm run build` → смок-чеклист на стенде →
деплой glb → золотой шаблон (dev-f7). app id `spreed`, схема БД, OCS API v4/bot v1/HMAC — НЕ трогаем
(транскрипция R5, HPB, мобильные клиенты). Первый релиз f7.1 — только маркер версии, обкатка конвейера.
+35
View File
@@ -0,0 +1,35 @@
# Паритет форка f7_talk с боевым glb.f7cloud.ru
Полный разбор: установленный на glb `spreed` = **сток 22.0.12 + ДВА слоя**.
## Слой 1 — ядро (НАШ, в форке)
Единственная функциональная правка PHP-ядра поверх стока:
- `lib/Notification/Listener.php` — форс языка push-уведомлений больших звонков (`ru`).
Инкорпорирован в форк (коммит f7.1). ⚠️ хардкод `ru` теряет per-user язык и конфликтует с
задачей мультиязычности З5 → кандидат вынести в config, согласование с dev-f7.
Всё остальное ядро (lib/, templates/, appinfo/, composer) — байт-в-байт сток. JS собирается из
исходников воспроизводимо (BUILD-f7.md).
## Слой 2 — брендинг (ЗОНА dev-f7, НЕ в форке)
Пост-сборочные/пост-установочные преобразования артефакта (generalize/theme-конвейер dev-f7):
- `l10n/*` (110 файлов): строки Nextcloud→F7cloud, docs-URL;
- `img/*` (27): фавиконки/иконки бренда;
- `css/talk-main.css`: одна @media-правка;
- namespace в собранных JS: `http://nextcloud.com/ns``https://f7cloud.ru/ns` (приходит из
зависимости, заменяется в бандле ПОСЛЕ сборки);
- бренд-строки в JS (видимый текст), НО НЕ внутренние идентификаторы (напр. cookie
`_nextcloudCsrfTokenReloaded` на glb СОХРАНЁН) — трансформация ХИРУРГИЧЕСКАЯ.
Точные правила этого слоя — в репозитории dev-f7 (не реконструирую: их зона). Для полного
glb-идентичного артефакта слой 2 применяется к сборке форка downstream.
## Итог: как собрать glb-идентичный артефакт
```
1. npm ci && npm run build (форк → сток-эквивалентный js) [dev-conf]
2. Listener.php-патч уже в форке (f7.1) [dev-conf]
3. брендинг-трансформ dev-f7 на артефакт (l10n/img/css/ns/строки) [dev-f7] ← НУЖНО от dev-f7
4. упаковка + подпись + публикация в App Store [dev-appstore]
```
Открытый вопрос к dev-f7: слой 2 остаётся вашим пост-шагом на артефакте форка, или переносим в
пайплайн форка отдельным коммитом-слоем? (письмо отправлено). До ответа форк = ядро-паритет с glb.
+4 -1
View File
@@ -18,11 +18,14 @@
* 🌉 **Sync with other chat solutions** With [Matterbridge](https://github.com/42wim/matterbridge/) being integrated in Talk, you can easily sync a lot of other chat solutions to Nextcloud Talk and vice-versa. * 🌉 **Sync with other chat solutions** With [Matterbridge](https://github.com/42wim/matterbridge/) being integrated in Talk, you can easily sync a lot of other chat solutions to Nextcloud Talk and vice-versa.
]]></description> ]]></description>
<version>22.0.12</version> <!-- F7-релиз форка: 4-й компонент = наш номер (22.0.12.N = 22.0.12-f7.N).
NC требует числовую версию, поэтому не «-f7.1». -->
<version>22.0.12.1</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>Anna Larch</author> <author>Anna Larch</author>
<author>Daniel Calviño Sánchez</author> <author>Daniel Calviño Sánchez</author>
<author>F7 dev-conf (форк)</author>
<author>Dorra Jaouad</author> <author>Dorra Jaouad</author>
<author>Grigorii Shartsev</author> <author>Grigorii Shartsev</author>
<author>Ivan Sein</author> <author>Ivan Sein</author>
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Сборка полного деплой-артефакта форка Talk (f7_talk).
# Пока брендинг dev-f7 и подпись dev-appstore не подключены — даёт ЯДРО-артефакт,
# идентичный glb по коду (без брендинга). Запуск на nd3 из корня клона f7_talk.
set -euo pipefail
VER="${1:?укажи версию, напр. 22.0.12.1}"
NODE=/home/foradmin/f7-build/node-v22.17.0-linux-x64/bin
REL_TAG="v22.0.12" # пиннированный апстрим-релиз для vendor
WORK="$(cd "$(dirname "$0")" && pwd)"
OUT="/home/foradmin/f7-build/artifact/spreed"
echo "== 1. Фронтенд: npm ci + build (наша сборка = офиц. релиз, BUILD-f7.md) =="
export PATH="$NODE:$PATH" NODE_OPTIONS=--max-old-space-size=8192
npm ci --no-audit --no-fund
npm run build
echo "== 2. Серверные PHP-зависимости (lib/Vendor) =="
# Вариант по умолчанию: берём детерминированный vendor из пиннированного апстрим-релиза
# (composer.lock фиксирован → идентично composer install). При ИЗМЕНЕНИИ PHP-зависимостей
# нужен PHP 8.3 + Composer на сборочном хосте (на nd3 их нет — см. TODO пайплайна).
REL_DIR="/home/foradmin/f7-build/rel/spreed"
if [ ! -d "$REL_DIR/lib/Vendor" ]; then
echo "нет релизного vendor — скачай spreed-$REL_TAG.tar.gz из nextcloud-releases и распакуй в $REL_DIR"; exit 1
fi
echo "== 3. Сборка артефакта =="
rm -rf "$OUT"; mkdir -p "$OUT"
cp -a "$REL_DIR/." "$OUT/" # база: серверная часть + vendor
cp -a "$WORK/js/." "$OUT/js/" # наши бандлы поверх
cp "$WORK/lib/Notification/Listener.php" "$OUT/lib/Notification/Listener.php" # наш патч ядра
cp "$WORK/appinfo/info.xml" "$OUT/appinfo/info.xml"
rm -f "$OUT/appinfo/signature.json" # апстрим-подпись невалидна — переподпишет dev-appstore
echo "== 4. TODO (внешние входы, см. mail/033 dev-appstore, mail/034 dev-f7) =="
echo " - брендинг dev-f7 (l10n/img/css/namespace/строки) → полный glb-идентичный вид"
echo " - подпись dev-appstore (свой CA) → NC integrity-check пройдёт"
echo " - смок-чеклист на ТЕСТ-стенде (не glb!) перед деплоем"
echo "Готово: $OUT (версия $VER). Это ЯДРО-артефакт (без брендинга/подписи)."
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
header.app-sidebar-header.hidden-by-call>div:not(.talk-sidebar-callview){display:none!important}#call-container[data-v-5dc1cd4a]{max-height:56.25%;padding-bottom:56.25%;position:relative;overflow:hidden}.call-loading[data-v-5dc1cd4a]{background-color:#000000b3;max-height:56.25%;padding-bottom:56.25%}
/*# sourceMappingURL=files-sidebar-call-chunk.chunk.css.map*/
@@ -0,0 +1 @@
{"version":3,"file":"../css/chunks/files-sidebar-call-chunk.chunk.css","sources":["webpack:///talk/src/views/FilesSidebarCallView.vue"],"sourcesContent":["\nheader.app-sidebar-header.hidden-by-call > div:not(.talk-sidebar-callview), {\n\tdisplay: none !important;\n}\n"],"names":[],"mappings":"AACA,gGAEA,2GAYA"}
@@ -0,0 +1,2 @@
.drafts[data-v-3226be3e] .dialog__content{min-height:200px}.drafts__wrapper[data-v-3226be3e]{grid-gap:var(--default-grid-baseline);grid-template-columns:1fr 1fr;display:grid}.drafts__empty[data-v-3226be3e]{margin:0!important}.poll-editor__wrapper[data-v-524c4b0e]{align-items:flex-end;gap:var(--default-grid-baseline);display:flex}.poll-editor__caption[data-v-524c4b0e]{margin:calc(var(--default-grid-baseline)*2)0 var(--default-grid-baseline);color:var(--color-primary-element);font-weight:700}.poll-editor__option[data-v-524c4b0e]{align-items:flex-end;gap:var(--default-grid-baseline);width:100%;margin-bottom:calc(var(--default-grid-baseline)*2);display:flex}.poll-editor__settings[data-v-524c4b0e]{flex-direction:column;gap:4px;margin-bottom:8px;display:flex}.poll-editor__back-button[data-v-524c4b0e]{top:var(--default-grid-baseline);z-index:1;inset-inline-start:var(--default-grid-baseline);position:absolute!important}.internal-warning[data-v-680baaf2]{margin:var(--default-grid-baseline)!important}.talk-tab__wrapper[data-v-3e07a5ca]{height:100%;padding:var(--default-grid-baseline)0;flex-direction:column;justify-content:flex-end;display:flex}.talk-tab__call-button[data-v-3e07a5ca]{margin:0 auto calc(var(--default-grid-baseline)*2)}.talk-tab__chat-view[data-v-3e07a5ca]{overflow:hidden}
/*# sourceMappingURL=files-sidebar-tab-chunk.chunk.css.map*/
@@ -0,0 +1 @@
{"version":3,"file":"../css/chunks/files-sidebar-tab-chunk.chunk.css","sources":["webpack:///talk/src/components/PollViewer/PollDraftHandler.vue","webpack:///talk/src/components/PollViewer/PollEditor.vue","webpack:///talk/src/components/RightSidebar/InternalSignalingHint.vue","webpack:///talk/src/views/FilesSidebarChatView.vue"],"sourcesContent":["\n.drafts {\n\t:deep(.dialog__content) {\n\t\tmin-height: 200px;\n\t}\n\n\t&__wrapper {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: 1fr 1fr;\n\t\tgrid-gap: var(--default-grid-baseline);\n\t}\n\n\t&__empty {\n\t\tmargin: 0 !important;\n\t}\n}\n","\n.poll-editor {\n\t&__wrapper {\n\t\tdisplay: flex;\n\t\talign-items: flex-end;\n\t\tgap: var(--default-grid-baseline);\n\t}\n\n\t&__caption {\n\t\tmargin: calc(var(--default-grid-baseline) * 2) 0 var(--default-grid-baseline);\n\t\tfont-weight: bold;\n\t\tcolor: var(--color-primary-element);\n\t}\n\n\t&__option {\n\t\tdisplay: flex;\n\t\talign-items: flex-end;\n\t\tgap: var(--default-grid-baseline);\n\t\twidth: 100%;\n\t\tmargin-bottom: calc(var(--default-grid-baseline) * 2);\n\t}\n\n\t&__settings {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: 4px;\n\t\tmargin-bottom: 8px;\n\t}\n\n\t&__back-button {\n\t\tposition: absolute !important;\n\t\ttop: var(--default-grid-baseline);\n\t\tinset-inline-start: var(--default-grid-baseline);\n\t\tz-index: 1;\n\t}\n}\n","\n.internal-warning {\n\tmargin: var(--default-grid-baseline) !important;\n}\n","\n.talk-tab {\n\t&__wrapper {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: flex-end;\n\t\theight: 100%;\n\t\tpadding: var(--default-grid-baseline) 0;\n\t}\n\n\t&__call-button {\n\t\tmargin: 0 auto calc(var(--default-grid-baseline) * 2);\n\t}\n\n\t&__chat-view {\n\t\toverflow: hidden;\n\t}\n}\n"],"names":[],"mappings":"AAEC,2DAIA,mHAMA,mDCVA,0GAMA,oKAMA,uKAQA,qGAOA,kKC5BD,iFCCC,kJAQA,2FAIA"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
.material-design-icon[data-v-3d24879b]{justify-content:center;place-self:center;align-items:center;display:flex}.color-picker[data-v-3d24879b]{padding:var(--border-radius-element);min-width:calc(4*var(--default-clickable-area) + 2*var(--border-radius-element));flex-direction:column;place-content:flex-end space-between;display:flex;overflow:hidden}.color-picker--clearable[data-v-3d24879b]{min-width:calc(5*var(--default-clickable-area) + 2*var(--border-radius-element))}.color-picker--advanced-fields[data-v-3d24879b]{min-width:264px}.color-picker__clear[data-v-3d24879b]{color:var(--color-main-text)}.color-picker__clear[data-v-3d24879b]:hover:not(:has(:checked)){color:var(--color-text-maxcontrast)}.color-picker__simple[data-v-3d24879b]{grid-template-columns:repeat(auto-fit,var(--default-clickable-area));grid-auto-rows:var(--default-clickable-area);display:grid}.color-picker__simple-color-circle[data-v-3d24879b]{width:calc(var(--default-clickable-area) - 10px);height:calc(var(--default-clickable-area) - 10px);min-height:calc(var(--default-clickable-area) - 10px);color:#fff;border:1px solid #00000040;border-radius:50%;justify-content:center;align-items:center;margin:auto;padding:0;font-size:16px;display:flex}.color-picker__simple-color-circle[data-v-3d24879b]:focus-within{outline:2px solid var(--color-main-text)}.color-picker__simple-color-circle[data-v-3d24879b]:hover{opacity:.6}.color-picker__simple-color-circle--active[data-v-3d24879b]{width:calc(var(--default-clickable-area) - 6px);height:calc(var(--default-clickable-area) - 6px);min-height:calc(var(--default-clickable-area) - 6px);transition:all .1s ease-in-out;opacity:1!important}.color-picker__advanced[data-v-3d24879b]{box-shadow:none!important}.color-picker__navigation[data-v-3d24879b]{gap:var(--default-grid-baseline);margin-top:calc(2*var(--default-grid-baseline));flex-direction:row;justify-content:space-between;display:flex}[data-v-3d24879b] .vc-chrome{width:unset;background-color:var(--color-main-background)}[data-v-3d24879b] .vc-chrome-color-wrap{width:30px;height:30px}[data-v-3d24879b] .vc-chrome-active-color{border-radius:17px}[data-v-3d24879b] .vc-chrome-body{background-color:var(--color-main-background);padding:14px 0 0}[data-v-3d24879b] .vc-chrome-body .vc-input__input{--input-border-radius:var(--border-radius-element);--input-border-width-offset:calc(var(--border-width-input-focused,2px) - var(--border-width-input,2px));width:100%;height:var(--default-clickable-area);padding-inline:calc(var(--border-radius-element) + var(--input-border-width-offset));padding-block:var(--input-border-width-offset);border:var(--border-width-input,2px)solid var(--color-border-maxcontrast);border-radius:var(--input-border-radius);font-size:var(--default-font-size);color:var(--color-main-text);box-shadow:none;margin:0}[data-v-3d24879b] .vc-chrome-body .vc-input__input:active:not([disabled]),[data-v-3d24879b] .vc-chrome-body .vc-input__input:hover:not([disabled]),[data-v-3d24879b] .vc-chrome-body .vc-input__input:focus:not([disabled]){--input-border-width-offset:0px;border-color:var(--color-main-text);border-width:var(--border-width-input-focused,2px);box-shadow:0 0 0 2px var(--color-main-background)!important}[data-v-3d24879b] .vc-chrome-body .vc-input__input:active:not([disabled])+.vc-input__label,[data-v-3d24879b] .vc-chrome-body .vc-input__input:hover:not([disabled])+.vc-input__label,[data-v-3d24879b] .vc-chrome-body .vc-input__input:focus:not([disabled])+.vc-input__label{color:var(--color-main-text)}[data-v-3d24879b] .vc-chrome-body .vc-input__label{inset-inline:var(--border-width-input-focused,2px);max-width:fit-content;margin-inline:calc(var(--border-radius-element) - var(--default-grid-baseline));padding-inline:var(--default-grid-baseline);font-family:var(--font-face);font-size:var(--font-size-small,13px);color:var(--color-text-maxcontrast);background-color:var(--color-main-background);pointer-events:none;margin-block:0;font-weight:500;line-height:1.5;position:absolute;inset-block-start:calc(-1.5*var(--font-size-small,13px)/2)}[data-v-3d24879b] .vc-chrome-toggle-btn{width:var(--default-clickable-area);height:var(--default-clickable-area);filter:var(--background-invert-if-dark);justify-content:center;align-items:center;margin-inline-start:6px;display:flex}[data-v-3d24879b] .vc-chrome-toggle-icon{width:24px;height:24px;margin:0}[data-v-3d24879b] .vc-chrome-toggle-icon-highlight{width:var(--default-clickable-area);height:var(--default-clickable-area);inset:0}[data-v-3d24879b] .vc-chrome-saturation-wrap{border-radius:3px}[data-v-3d24879b] .vc-chrome-saturation-circle{width:20px;height:20px}.slide-enter-from[data-v-3d24879b]{opacity:0;transform:translate(-50%)}.slide-enter-to[data-v-3d24879b],.slide-leave-from[data-v-3d24879b]{opacity:1;transform:translate(0)}.slide-leave-to[data-v-3d24879b]{opacity:0;transform:translate(-50%)}.slide-enter-active[data-v-3d24879b],.slide-leave-active[data-v-3d24879b]{transition:all 50ms ease-in-out}
/*# sourceMappingURL=node_modules_nextcloud_vue_dist_assets_NcColorPicker-CO_Jq2Ow_css.chunk.css.map*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,45 @@
# Фикс: лампочка камеры горит при выключенном видео в звонке
**Ветка:** `fix/camera-led-preview` · **Статус:** реализовано, СБОРКА OK, **ждёт тест-фазу** (не деплоено).
## Симптом
Пользователь входит в конференцию с выключенной камерой (или выключает её). Своего видео
в звонке нет — но индикатор камеры ноутбука ГОРИТ, будто камера используется. Приватностный баг.
## Первопричина (по исходникам, высокая уверенность)
Два независимых слоя работы с камерой:
1. **Медиа-конвейер звонка** (`utils/media/pipeline/MediaDevicesSource.js`) — при выключении видео
вызывает `setVideoAllowed(false)``track.stop()`. Камеру отпускает КОРРЕКТНО.
2. **Превью-подсистема** (`composables/useDevices.js`) — используется диалогом настроек И
контрол-кнопками звонка. `initializeDevices()` БЕЗУСЛОВНО грабит камеру:
`updateVideoStream()``getUserMedia({video:true})`. Отпускает только когда отписались ВСЕ.
Виновник — контрол-кнопки: `LocalVideoControlButton.vue` и `LocalAudioControlButton.vue` на
`mounted()` зовут `subscribeToDevices()` и держат подписку ВЕСЬ звонок (`beforeUnmount` = конец
звонка). Первый же подписчик поднимает `initializeDevices()` → камера включается и горит всё время,
хотя кнопкам нужен лишь СПИСОК устройств для меню выбора, а не живой поток. У кнопок нет `<video>`
превью — поток не показывается, просто удерживает устройство.
Проверено: `MediaDevicesManager.enableDeviceEvents()` берёт список через `enumerateDevices()`
камеру НЕ трогает. Значит список для меню доступен без превью-потока.
## Фикс
Разделили в `useDevices` два вида подписки:
- **список устройств** (нужен всем, камеру не трогает);
- **живой превью-поток** (нужен только диалогу настроек, где есть `<video>`).
Изменения:
- `useDevices.js`: новый счётчик `streamSubscribersCount`; `subscribeToDevices({requestStream})` /
`unsubscribeFromDevices({requestStream})`; ЕДИНАЯ точка контроля — `updateAudioStream()`/
`updateVideoStream()` при `streamSubscribersCount===0` не грабят и останавливают поток (защищает
и от `watch(videoInputId)`); `initializeDevices` поднимает потоки только при наличии превью-подписчика.
- `LocalVideoControlButton.vue`, `LocalAudioControlButton.vue`: `subscribeToDevices({requestStream:false})`.
- `MediaSettings.vue`: без изменений — по умолчанию `requestStream:true` (превью в диалоге работает).
## Что проверить в тест-фазе
1. Вход в звонок с выключенной камерой → лампочка НЕ горит; видео нет. (главный кейс)
2. Диалог настроек мультимедиа → превью камеры/микрофона работает; при закрытии камера гаснет.
3. Включение видео в звонке → камера работает, видео идёт; выключение → лампочка гаснет.
4. Смена камеры/микрофона в меню кнопки во время звонка.
5. Виртуальный фон в превью настроек.
6. Несколько вкладок/повторные входы — нет «залипшего» потока.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More