Files
FoxBrowser/25.09.2026.md
T
2026-10-01 01:46:18 +03:00

140 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
УВАГА: Термінал агента не працює. Не виконуй жодних команд (dotnet build,
dotnet restore, dotnet run, встановлення NuGet-пакетів тощо) самостійно.
Якщо для задачі щось треба встановити, оновити чи запустити — напиши це
явним окремим пунктом "Потрібно виконати вручну:" в кінці відповіді для
цієї задачі, і не намагайся обійти це через bash/термінал.
Реалізуй дві задачі в FoxBrowser. Роби послідовно, кожну — окремим описом,
що змінено і як перевірити вручну (агент працює в Linux sandbox без
dotnet/WPF runtime — фінальний тест виконує користувач на Windows).
## 1. Діагностика й виправлення кнопки "Розширення"
Кнопка налаштувань розширень (`ExtensionsSettingsWindow`) працює
неправильно. Перевір по черзі всі гіпотези нижче, знайди реальну причину
в коді (не вигадуй, яка з них правильна, — прочитай файли й перевір),
і виправ саме те, що підтвердиться. Якщо підтвердиться кілька — виправ усі.
### 1a. Recovery-fallback environment без AreBrowserExtensionsEnabled
- Знайти в `MainWindow`/`TabManager` весь код навколо recovery-гілки з
`NEXT_AGENT_GUIDE`/інструкції ("Startup recovery fix — 0x8007139F") —
місце, де при HRESULT `0x8007139F` створюється запасний
`CoreWebView2Environment` з тимчасовою user-data folder.
- Перевірити: чи цей запасний environment створюється через ту саму
функцію/той самий `CoreWebView2EnvironmentOptions` з
`AreBrowserExtensionsEnabled = true`, що й основний, чи через окремий
шматок коду, де цей прапорець забули виставити.
- Якщо прапорець не потрапляє в recovery-гілку — винести створення
`CoreWebView2EnvironmentOptions` в один спільний метод/константу, яку
використовують і основний, і recovery шлях, щоб розбіжність стала
неможливою в принципі, а не просто додати прапорець ще раз у другому місці.
- Додати явний лог/статус (напр. поле `bool ExtensionsAvailable` на
TabManager чи MainWindow), який ExtensionsSettingsWindow може прочитати
при відкритті — і якщо `false` (бо стартанули в recovery-режимі),
показати користувачу зрозуміле повідомлення в самому вікні
("Розширення недоступні в цьому сеансі — застосунок запустився в
режимі відновлення профілю, перезапусти FoxBrowser"), а не порожній
список без пояснень.
### 1b. IsEnabled read-only і биндинг чекбокса
- Знайти XAML розмітку списку розширень в `ExtensionsSettingsWindow.xaml`.
- Перевірити: чи `IsChecked` чекбокса прив'язаний напряму двостороннім
біндингом до `Extension.IsEnabled` (read-only властивість), чи через
`Checked`/`Unchecked` event-обробник (або Command), що явно викликає
`await extension.EnableAsync(bool)`.
- Якщо це прямий `TwoWay`-біндинг на read-only властивість — замінити на
`OneWay`-біндинг для відображення поточного стану + окремий
`Click`/`Checked`/`Unchecked` обробник, який викликає `EnableAsync()`,
чекає результат, і тільки після успіху оновлює UI-стан (checkbox),
а при помилці — повертає checkbox у попередній стан і показує повідомлення.
### 1c. FolderBrowserDialog без owner-вікна
- Знайти виклик `FolderBrowserDialog`/`OpenFileDialog` для "Додати
розширення" в `ExtensionsSettingsWindow.xaml.cs`.
- Перевірити, чи передається owner-handle:
`new System.Windows.Interop.WindowInteropHelper(this).Handle`
через `IWin32Window`-обгортку (WinForms-діалог вимагає `IWin32Window`,
не голий `IntPtr` — якщо ще нема обгортки-хелпера, додати простий
`NativeWindowWrapper : IWin32Window`).
- Якщо owner не передається — додати, щоб діалог відкривався поверх
`ExtensionsSettingsWindow`, а не міг ховатись позаду.
### 1d. Options-сторінка розширення через спільний WebView2
- Знайти обробник кнопки "Налаштування" (per-extension), що відкриває
`chrome-extension://<id>/options.html`.
- Перевірити: чи ця навігація йде через ТОЙ САМИЙ спільний `CoreWebView2`,
яким керує `TabManager` для звичайних вкладок, чи через окремий
`CoreWebView2Controller`, створений безпосередньо в
`ExtensionsSettingsWindow`.
- Якщо використовується спільний контрол — це помилка архітектури: клік
по "Налаштування" в діалозі може непомітно перекидати активну вкладку
користувача в головному вікні. Виправити: створити в
`ExtensionsSettingsWindow` власний ізольований `CoreWebView2Controller`
(з того самого `CoreWebView2Environment`, щоб профіль/розширення
збігались) — тільки для options-сторінок, ніколи не займаючи головний
спільний WebView2.
Після кожного виправленого пункту (1a-1d) — короткий підсумок і ручний
тест-сценарій для Windows.
## 2. Звук WebView2 у Volume Mixer як "FoxBrowser"
Додати `Core/AudioSessionLabeler.cs`, який перейменовує WASAPI
audio-сесії власних дочірніх WebView2-процесів на "FoxBrowser" з іконкою
застосунку, БЕЗ ризику торкнутись чужих WebView2-сесій (Teams, Outlook,
системний Edge).
- Додати NuGet-пакет `NAudio` (зазнач це явно в "Потрібно виконати
вручну" — сам пакет не встановлюй, тільки допиши `<PackageReference>`
в `.csproj` вручну і попроси користувача зробити `dotnet restore`).
- Клас має:
1. Відстежувати список PID усіх дочірніх `msedgewebview2.exe`-процесів,
які належать саме FoxBrowser (ті самі, що вже прив'язані через
Job Object з попередньої задачі про дерево процесів —
переюзати ту логіку, не дублювати).
2. Через `NAudio.CoreAudioApi.MMDeviceEnumerator` отримати default
render endpoint (`eRender`, `eMultimedia`), і його `AudioSessionManager`.
3. Підписатись на подію нової сесії (`AudioSessionManager.SessionCreated`
в NAudio, або еквівалент `IAudioSessionNotification.OnSessionCreated`
якщо в NAudio такого немає в потрібній версії — перевір API
конкретної версії пакету, яку додаси).
4. У обробнику нової сесії: якщо `session.GetProcessID` входить у
список PID FoxBrowser — викликати
`session.DisplayName = "FoxBrowser"` і
`session.IconPath = Path.Combine(AppContext.BaseDirectory, "foxbrowser.ico")`
(або еквівалентні NAudio-методи `SetDisplayNameAsync`/властивості —
перевір актуальний API пакету).
5. **Критично:** ці властивості НЕ переживають життя об'єкта сесії
(задокументована поведінка WASAPI) — тому одноразового виклику при
старті недостатньо. Логіка з пункту 3-4 має спрацьовувати на КОЖНУ
нову сесію протягом усього часу роботи FoxBrowser, не тільки на старті.
6. НІКОЛИ не застосовувати `DisplayName`/`IconPath` до сесії, чий PID
не входить у явно відстежуваний список власних дочірніх процесів —
це і є захист від зачіпання чужих `msedgewebview2.exe` на машині
користувача.
- Покласти файл `foxbrowser.ico` в корінь проєкту поруч з іншими іконками
(якщо такого файлу ще нема в репозиторії — створи заглушку-примітивну
іконку і явно напиши користувачу в "Потрібно виконати вручну", що варто
замінити на нормальну).
- Викликати ініціалізацію `AudioSessionLabeler` один раз при старті
застосунку (напр. в `MainWindow` після успішної ініціалізації
`TabManager`, коли вже відомий перший дочірній PID).
Ручний тест Windows:
1. Запустити FoxBrowser, відкрити вкладку з YouTube, почати відтворення.
2. Відкрити Volume Mixer (правий клік на іконку гучності в треї Windows →
Open Volume mixer, або через Settings → System → Sound → Volume mixer).
3. Перевірити, що застосунок у списку показаний як "FoxBrowser" з іконкою
застосунку, а не як "Microsoft Edge WebView2"/msedgewebview2.exe.
4. Переключитись на іншу вкладку, знову увімкнути звук на новій —
перевірити, що лейбл лишається "FoxBrowser" і для нової audio-сесії
(не тільки для першої).
5. Паралельно запустити щось інше з WebView2 на цій же машині (напр.
Microsoft Teams, якщо є), перевірити, що ЙОГО лейбл у Volume Mixer
НЕ змінився і лишився своїм — це підтверджує, що фільтр по PID працює
правильно й не займає чужі процеси.