Changed how the built-in extensions work and fixed tab loading

This commit is contained in:
AlastorFox committed 2026-10-01 22:36:17 +03:00
1 parent 79c1d88b58
commit 4d916207a4
3 files changed
+90 -12

No files matched your search

+6
View File
@@ -38,6 +38,7 @@ public sealed class Session
public static class SessionStore public static class SessionStore
{ {
private static readonly string SessionPath = Path.Combine(AppContext.BaseDirectory, "session.json"); private static readonly string SessionPath = Path.Combine(AppContext.BaseDirectory, "session.json");
private static readonly SemaphoreSlim SaveGate = new(1, 1);
private static readonly JsonSerializerOptions JsonOptions = new() private static readonly JsonSerializerOptions JsonOptions = new()
{ {
@@ -47,6 +48,7 @@ public static class SessionStore
public static async Task SaveAsync(IEnumerable<BrowserTab> tabs, int activeIndex) public static async Task SaveAsync(IEnumerable<BrowserTab> tabs, int activeIndex)
{ {
await SaveGate.WaitAsync();
try try
{ {
var snapshots = tabs.Select(t => new TabSnapshot var snapshots = tabs.Select(t => new TabSnapshot
@@ -83,6 +85,10 @@ public static class SessionStore
{ {
System.Diagnostics.Debug.WriteLine($"[SessionStore] Save failed: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"[SessionStore] Save failed: {ex.Message}");
} }
finally
{
SaveGate.Release();
}
} }
public static async Task<Session?> LoadAsync() public static async Task<Session?> LoadAsync()
+70 -9
View File
@@ -26,6 +26,7 @@ public sealed class TabManager : IAsyncDisposable
private bool _minimizedMode; private bool _minimizedMode;
private bool _navigationInProgress; private bool _navigationInProgress;
private bool _switchInProgress; private bool _switchInProgress;
private bool _restoringSession;
private readonly string _blockedElementsPath = Path.Combine(AppContext.BaseDirectory, "blocked-elements.json"); private readonly string _blockedElementsPath = Path.Combine(AppContext.BaseDirectory, "blocked-elements.json");
private readonly Dictionary<string, List<string>> _blockedElements; private readonly Dictionary<string, List<string>> _blockedElements;
@@ -43,6 +44,7 @@ public sealed class TabManager : IAsyncDisposable
public BrowserTab? ActiveTab { get; private set; } public BrowserTab? ActiveTab { get; private set; }
public bool IsMinimizedMode => _minimizedMode; public bool IsMinimizedMode => _minimizedMode;
public bool ExtensionsAvailable { get; private set; } public bool ExtensionsAvailable { get; private set; }
public bool SessionReady { get; private set; }
public CoreWebView2Environment Environment => _environment; public CoreWebView2Environment Environment => _environment;
public WebView2 View => _view; public WebView2 View => _view;
public ExtensionManager? ExtensionManager { get; private set; } public ExtensionManager? ExtensionManager { get; private set; }
@@ -68,7 +70,17 @@ public sealed class TabManager : IAsyncDisposable
_view.CoreWebView2.IsDocumentPlayingAudioChanged += OnAudioStateChanged; _view.CoreWebView2.IsDocumentPlayingAudioChanged += OnAudioStateChanged;
_view.CoreWebView2.HistoryChanged += OnHistoryChanged; _view.CoreWebView2.HistoryChanged += OnHistoryChanged;
_view.CoreWebView2.WebMessageReceived += OnWebMessageReceived; _view.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
await RestoreSessionOrDefaultAsync(); _restoringSession = true;
try
{
await RestoreSessionOrDefaultAsync();
}
finally
{
_restoringSession = false;
SessionReady = true;
}
await SaveSessionAsync();
} }
public async Task SaveSessionAsync() public async Task SaveSessionAsync()
@@ -129,7 +141,9 @@ public sealed class TabManager : IAsyncDisposable
_audioOnly = tab.IsAudioOnly; _audioOnly = tab.IsAudioOnly;
ActiveTabStateChanged?.Invoke(this, EventArgs.Empty); ActiveTabStateChanged?.Invoke(this, EventArgs.Empty);
_navigationInProgress = true; _navigationInProgress = true;
await UpdateDocumentCreatedScriptAsync();
core.Navigate(tab.Address); core.Navigate(tab.Address);
if (!_restoringSession) await SaveSessionAsync();
await Task.Yield(); await Task.Yield();
} }
finally { _switchInProgress = false; } finally { _switchInProgress = false; }
@@ -143,6 +157,7 @@ public sealed class TabManager : IAsyncDisposable
tab.Address = NormalizeAddress(address); tab.Address = NormalizeAddress(address);
if (ActiveTab != tab) { await SwitchToTabAsync(tab); return; } if (ActiveTab != tab) { await SwitchToTabAsync(tab); return; }
_navigationInProgress = true; _navigationInProgress = true;
await UpdateDocumentCreatedScriptAsync();
core.Navigate(tab.Address); core.Navigate(tab.Address);
} }
@@ -276,13 +291,20 @@ public sealed class TabManager : IAsyncDisposable
public void GoForward() { var core = _view.CoreWebView2; if (core?.CanGoForward == true) core.GoForward(); } public void GoForward() { var core = _view.CoreWebView2; if (core?.CanGoForward == true) core.GoForward(); }
public void Reload() { var core = _view.CoreWebView2; if (core is null) return; _navigationInProgress = true; core.Reload(); } public void Reload() { var core = _view.CoreWebView2; if (core is null) return; _navigationInProgress = true; core.Reload(); }
public void CloseTab(BrowserTab tab) public async Task CloseTabAsync(BrowserTab tab)
{ {
var index = Tabs.IndexOf(tab); var index = Tabs.IndexOf(tab);
if (index < 0) return;
Tabs.Remove(tab); Tabs.Remove(tab);
if (Tabs.Count == 0) { _ = AddTabAsync(); return; } if (Tabs.Count == 0)
if (ActiveTab == tab) _ = SwitchToTabAsync(Tabs[Math.Min(index, Tabs.Count - 1)]); {
_ = SaveSessionAsync(); await AddTabAsync();
return;
}
if (ActiveTab == tab)
await SwitchToTabAsync(Tabs[Math.Min(index, Tabs.Count - 1)]);
else
await SaveSessionAsync();
} }
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
@@ -367,6 +389,47 @@ public sealed class TabManager : IAsyncDisposable
try { await _view.CoreWebView2.ExecuteScriptAsync(script); } catch { } try { await _view.CoreWebView2.ExecuteScriptAsync(script); } catch { }
} }
private async Task UpdateDocumentCreatedScriptAsync()
{
var core = _view.CoreWebView2;
if (core is null) return;
var host = GetCurrentHost();
var selectors = host is not null && _blockedElements.TryGetValue(host, out var savedSelectors)
? savedSelectors
: new List<string>();
var darkEnabled = ActiveTab?.IsDarkMode == true &&
Uri.TryCreate(ActiveTab.Address, UriKind.Absolute, out var address) &&
(address.Scheme == Uri.UriSchemeHttp || address.Scheme == Uri.UriSchemeHttps);
var brightness = (ActiveTab?.DarkBrightness ?? 0.72).ToString(System.Globalization.CultureInfo.InvariantCulture);
var contrast = (ActiveTab?.DarkContrast ?? 1.08).ToString(System.Globalization.CultureInfo.InvariantCulture);
var saturation = (ActiveTab?.DarkSaturation ?? 0.88).ToString(System.Globalization.CultureInfo.InvariantCulture);
var script = """
(()=>{
const selectors=__SELECTORS__, dark=__DARK__, brightness=__BRIGHTNESS__, contrast=__CONTRAST__, saturation=__SATURATION__;
const apply=()=>{
const root=document.documentElement;
if(!root){setTimeout(apply,0);return;}
let darkStyle=document.getElementById('fox-dark-mode');
if(!darkStyle){darkStyle=document.createElement('style');darkStyle.id='fox-dark-mode';root.appendChild(darkStyle);}
let blockedStyle=document.getElementById('fox-blocked-elements');
if(!blockedStyle){blockedStyle=document.createElement('style');blockedStyle.id='fox-blocked-elements';root.appendChild(blockedStyle);}
const darkCss=dark?'html{background:#111!important;color-scheme:dark!important}html.fox-dark-mode{background:#111!important;color-scheme:dark!important}html.fox-dark-mode body{background-color:#15171b!important;filter:brightness('+brightness+') contrast('+contrast+') saturate('+saturation+')!important}html.fox-dark-mode input,html.fox-dark-mode textarea,html.fox-dark-mode select,html.fox-dark-mode button{color-scheme:dark!important}':'';
darkStyle.textContent=darkCss;
blockedStyle.textContent=selectors.map(x=>x+'{display:none!important;}').join('');
if(dark) root.classList.add('fox-dark-mode'); else root.classList.remove('fox-dark-mode');
};
apply();
})();
"""
.Replace("__SELECTORS__", JsonSerializer.Serialize(selectors), StringComparison.Ordinal)
.Replace("__DARK__", darkEnabled ? "true" : "false", StringComparison.Ordinal)
.Replace("__BRIGHTNESS__", brightness, StringComparison.Ordinal)
.Replace("__CONTRAST__", contrast, StringComparison.Ordinal)
.Replace("__SATURATION__", saturation, StringComparison.Ordinal);
try { await core.AddScriptToExecuteOnDocumentCreatedAsync(script); } catch { }
}
private string? GetCurrentHost() private string? GetCurrentHost()
{ {
return Uri.TryCreate(ActiveTab?.Address, UriKind.Absolute, out var uri) && return Uri.TryCreate(ActiveTab?.Address, UriKind.Absolute, out var uri) &&
@@ -470,11 +533,9 @@ public sealed class TabManager : IAsyncDisposable
const root=document.documentElement; const root=document.documentElement;
if(!root)return; if(!root)return;
root.classList.add('fox-dark-mode'); root.classList.add('fox-dark-mode');
document.getElementById('fox-dark-mode')?.remove(); let s=document.getElementById('fox-dark-mode');
const s=document.createElement('style'); if(!s){s=document.createElement('style');s.id='fox-dark-mode';(document.head||root).appendChild(s);}
s.id='fox-dark-mode';
s.textContent=`html.fox-dark-mode{background:#111!important;color-scheme:dark!important}html.fox-dark-mode body{background-color:#15171b!important;filter:brightness(__BRIGHTNESS__) contrast(__CONTRAST__) saturate(__SATURATION__)!important}html.fox-dark-mode input,html.fox-dark-mode textarea,html.fox-dark-mode select,html.fox-dark-mode button{color-scheme:dark!important}`; s.textContent=`html.fox-dark-mode{background:#111!important;color-scheme:dark!important}html.fox-dark-mode body{background-color:#15171b!important;filter:brightness(__BRIGHTNESS__) contrast(__CONTRAST__) saturate(__SATURATION__)!important}html.fox-dark-mode input,html.fox-dark-mode textarea,html.fox-dark-mode select,html.fox-dark-mode button{color-scheme:dark!important}`;
(document.head||root).appendChild(s);
})(); })();
""" """
: """ : """
+14 -3
View File
@@ -19,6 +19,7 @@ public partial class MainWindow : Window
private TabManager? _tabManager; private TabManager? _tabManager;
private TrayIconManager? _tray; private TrayIconManager? _tray;
private bool _allowClose; private bool _allowClose;
private bool _closingAfterSessionSave;
private readonly DispatcherTimer _watchdogTimer = new() { Interval = TimeSpan.FromSeconds(30) }; private readonly DispatcherTimer _watchdogTimer = new() { Interval = TimeSpan.FromSeconds(30) };
private AudioSessionLabeler? _audioLabeler; private AudioSessionLabeler? _audioLabeler;
private bool _updatingDarkModeMenu; private bool _updatingDarkModeMenu;
@@ -149,6 +150,7 @@ public partial class MainWindow : Window
_tabManager.ActiveTabStateChanged += (_, _) => Dispatcher.Invoke(RefreshAddressBar); _tabManager.ActiveTabStateChanged += (_, _) => Dispatcher.Invoke(RefreshAddressBar);
DataContext = _tabManager; DataContext = _tabManager;
await _tabManager.InitializeAsync(); await _tabManager.InitializeAsync();
TabStrip.SelectedItem = _tabManager.ActiveTab;
var iconPath = ResolveAppIconPath(_appSettings); var iconPath = ResolveAppIconPath(_appSettings);
try try
{ {
@@ -330,15 +332,16 @@ public partial class MainWindow : Window
private async void TabStrip_SelectionChanged(object sender, SelectionChangedEventArgs e) private async void TabStrip_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (e.Source != TabStrip || TabStrip.SelectedItem is not BrowserTab tab || _tabManager is null) return; if (e.Source != TabStrip || TabStrip.SelectedItem is not BrowserTab tab || _tabManager is null || !_tabManager.SessionReady) return;
AddressBox.Text = tab.Address; AddressBox.Text = tab.Address;
await _tabManager.SwitchToTabAsync(tab); await _tabManager.SwitchToTabAsync(tab);
RefreshAddressBar(); RefreshAddressBar();
} }
private void CloseTab_Click(object sender, RoutedEventArgs e) private async void CloseTab_Click(object sender, RoutedEventArgs e)
{ {
if ((sender as System.Windows.Controls.Button)?.Tag is BrowserTab tab) _tabManager?.CloseTab(tab); if ((sender as System.Windows.Controls.Button)?.Tag is BrowserTab tab && _tabManager is not null)
await _tabManager.CloseTabAsync(tab);
RefreshAddressBar(); RefreshAddressBar();
} }
@@ -360,6 +363,14 @@ public partial class MainWindow : Window
} }
else else
{ {
if (!_closingAfterSessionSave)
{
e.Cancel = true;
_closingAfterSessionSave = true;
if (_tabManager is not null) await _tabManager.SaveSessionAsync();
Close();
return;
}
_watchdogTimer.Stop(); _watchdogTimer.Stop();
_tray?.Dispose(); _tray?.Dispose();
_audioLabeler?.Dispose(); _audioLabeler?.Dispose();