Changed how the built-in extensions work and fixed tab loading
This commit is contained in:
1 parent
79c1d88b58
commit
4d916207a4
3 files changed
+90
-12
No files matched your search
@@ -38,6 +38,7 @@ public sealed class Session
|
||||
public static class SessionStore
|
||||
{
|
||||
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()
|
||||
{
|
||||
@@ -47,6 +48,7 @@ public static class SessionStore
|
||||
|
||||
public static async Task SaveAsync(IEnumerable<BrowserTab> tabs, int activeIndex)
|
||||
{
|
||||
await SaveGate.WaitAsync();
|
||||
try
|
||||
{
|
||||
var snapshots = tabs.Select(t => new TabSnapshot
|
||||
@@ -83,6 +85,10 @@ public static class SessionStore
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[SessionStore] Save failed: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
SaveGate.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<Session?> LoadAsync()
|
||||
|
||||
+70
-9
@@ -26,6 +26,7 @@ public sealed class TabManager : IAsyncDisposable
|
||||
private bool _minimizedMode;
|
||||
private bool _navigationInProgress;
|
||||
private bool _switchInProgress;
|
||||
private bool _restoringSession;
|
||||
private readonly string _blockedElementsPath = Path.Combine(AppContext.BaseDirectory, "blocked-elements.json");
|
||||
private readonly Dictionary<string, List<string>> _blockedElements;
|
||||
|
||||
@@ -43,6 +44,7 @@ public sealed class TabManager : IAsyncDisposable
|
||||
public BrowserTab? ActiveTab { get; private set; }
|
||||
public bool IsMinimizedMode => _minimizedMode;
|
||||
public bool ExtensionsAvailable { get; private set; }
|
||||
public bool SessionReady { get; private set; }
|
||||
public CoreWebView2Environment Environment => _environment;
|
||||
public WebView2 View => _view;
|
||||
public ExtensionManager? ExtensionManager { get; private set; }
|
||||
@@ -68,7 +70,17 @@ public sealed class TabManager : IAsyncDisposable
|
||||
_view.CoreWebView2.IsDocumentPlayingAudioChanged += OnAudioStateChanged;
|
||||
_view.CoreWebView2.HistoryChanged += OnHistoryChanged;
|
||||
_view.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
|
||||
await RestoreSessionOrDefaultAsync();
|
||||
_restoringSession = true;
|
||||
try
|
||||
{
|
||||
await RestoreSessionOrDefaultAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_restoringSession = false;
|
||||
SessionReady = true;
|
||||
}
|
||||
await SaveSessionAsync();
|
||||
}
|
||||
|
||||
public async Task SaveSessionAsync()
|
||||
@@ -129,7 +141,9 @@ public sealed class TabManager : IAsyncDisposable
|
||||
_audioOnly = tab.IsAudioOnly;
|
||||
ActiveTabStateChanged?.Invoke(this, EventArgs.Empty);
|
||||
_navigationInProgress = true;
|
||||
await UpdateDocumentCreatedScriptAsync();
|
||||
core.Navigate(tab.Address);
|
||||
if (!_restoringSession) await SaveSessionAsync();
|
||||
await Task.Yield();
|
||||
}
|
||||
finally { _switchInProgress = false; }
|
||||
@@ -143,6 +157,7 @@ public sealed class TabManager : IAsyncDisposable
|
||||
tab.Address = NormalizeAddress(address);
|
||||
if (ActiveTab != tab) { await SwitchToTabAsync(tab); return; }
|
||||
_navigationInProgress = true;
|
||||
await UpdateDocumentCreatedScriptAsync();
|
||||
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 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);
|
||||
if (index < 0) return;
|
||||
Tabs.Remove(tab);
|
||||
if (Tabs.Count == 0) { _ = AddTabAsync(); return; }
|
||||
if (ActiveTab == tab) _ = SwitchToTabAsync(Tabs[Math.Min(index, Tabs.Count - 1)]);
|
||||
_ = SaveSessionAsync();
|
||||
if (Tabs.Count == 0)
|
||||
{
|
||||
await AddTabAsync();
|
||||
return;
|
||||
}
|
||||
if (ActiveTab == tab)
|
||||
await SwitchToTabAsync(Tabs[Math.Min(index, Tabs.Count - 1)]);
|
||||
else
|
||||
await SaveSessionAsync();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -367,6 +389,47 @@ public sealed class TabManager : IAsyncDisposable
|
||||
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()
|
||||
{
|
||||
return Uri.TryCreate(ActiveTab?.Address, UriKind.Absolute, out var uri) &&
|
||||
@@ -470,11 +533,9 @@ public sealed class TabManager : IAsyncDisposable
|
||||
const root=document.documentElement;
|
||||
if(!root)return;
|
||||
root.classList.add('fox-dark-mode');
|
||||
document.getElementById('fox-dark-mode')?.remove();
|
||||
const s=document.createElement('style');
|
||||
s.id='fox-dark-mode';
|
||||
let s=document.getElementById('fox-dark-mode');
|
||||
if(!s){s=document.createElement('style');s.id='fox-dark-mode';(document.head||root).appendChild(s);}
|
||||
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
@@ -19,6 +19,7 @@ public partial class MainWindow : Window
|
||||
private TabManager? _tabManager;
|
||||
private TrayIconManager? _tray;
|
||||
private bool _allowClose;
|
||||
private bool _closingAfterSessionSave;
|
||||
private readonly DispatcherTimer _watchdogTimer = new() { Interval = TimeSpan.FromSeconds(30) };
|
||||
private AudioSessionLabeler? _audioLabeler;
|
||||
private bool _updatingDarkModeMenu;
|
||||
@@ -149,6 +150,7 @@ public partial class MainWindow : Window
|
||||
_tabManager.ActiveTabStateChanged += (_, _) => Dispatcher.Invoke(RefreshAddressBar);
|
||||
DataContext = _tabManager;
|
||||
await _tabManager.InitializeAsync();
|
||||
TabStrip.SelectedItem = _tabManager.ActiveTab;
|
||||
var iconPath = ResolveAppIconPath(_appSettings);
|
||||
try
|
||||
{
|
||||
@@ -330,15 +332,16 @@ public partial class MainWindow : Window
|
||||
|
||||
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;
|
||||
await _tabManager.SwitchToTabAsync(tab);
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -360,6 +363,14 @@ public partial class MainWindow : Window
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_closingAfterSessionSave)
|
||||
{
|
||||
e.Cancel = true;
|
||||
_closingAfterSessionSave = true;
|
||||
if (_tabManager is not null) await _tabManager.SaveSessionAsync();
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
_watchdogTimer.Stop();
|
||||
_tray?.Dispose();
|
||||
_audioLabeler?.Dispose();
|
||||
|
||||
Reference in new issue
Block a user