Changed how the built-in extensions work and fixed tab loading
This commit is contained in:
1 parent
b6d40deffd
commit
85df7949e2
3 files changed
+89
-11
No files matched your search
@@ -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()
|
||||||
|
|||||||
+69
-8
@@ -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,8 +70,18 @@ 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;
|
||||||
|
_restoringSession = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
await RestoreSessionOrDefaultAsync();
|
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
@@ -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();
|
||||||
|
|||||||
Reference in new issue
Block a user