Files
LanMountainDesktop/LanMontainDesktop/Views/Components/BrowserWidget.axaml.cs
lincube 3d22c04a04 0.2.8
天气组件、倒计时组件微调。引入浏览器组件。
2026-03-04 03:41:59 +08:00

292 lines
8.8 KiB
C#

using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Styling;
using AvaloniaWebView;
using WebViewCore.Events;
namespace LanMontainDesktop.Views.Components;
public partial class BrowserWidget : UserControl, IDesktopComponentWidget
, IDesktopPageVisibilityAwareComponentWidget
{
private static readonly Uri DefaultHomeUri = new("https://www.bing.com");
private double _currentCellSize = 48;
private bool? _isNightModeApplied;
private Uri _lastKnownUri = DefaultHomeUri;
private bool _isOnActiveDesktopPage;
private bool _isEditMode;
private bool _isWebViewActive = true;
public BrowserWidget()
{
InitializeComponent();
SizeChanged += OnSizeChanged;
ActualThemeVariantChanged += OnActualThemeVariantChanged;
AttachedToVisualTree += OnAttachedToVisualTree;
DetachedFromVisualTree += OnDetachedFromVisualTree;
ApplyCellSize(_currentCellSize);
ApplyTheme(force: true);
BrowserWebView.NavigationStarting += OnBrowserWebViewNavigationStarting;
UpdateWebViewActiveState();
NavigateTo(DefaultHomeUri);
}
public void ApplyCellSize(double cellSize)
{
_currentCellSize = Math.Max(1, cellSize);
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.34, 12, 28));
RootBorder.Padding = new Thickness(
Math.Clamp(_currentCellSize * 0.20, 8, 18));
WebViewHostBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.24, 10, 22));
AddressBarBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.22, 10, 20));
AddressBarBorder.Padding = new Thickness(8, 6);
var rowSpacing = 8d;
if (RootBorder.Child is Grid rootGrid)
{
rootGrid.RowSpacing = rowSpacing;
}
var buttonSize = Math.Clamp(_currentCellSize * 0.72, 30, 36);
var buttonCorner = buttonSize * 0.5;
var iconSize = Math.Clamp(buttonSize * 0.44, 14, 16);
foreach (var button in new[] { RefreshButton, GoButton })
{
button.Width = buttonSize;
button.Height = buttonSize;
button.CornerRadius = new CornerRadius(buttonCorner);
}
if (RefreshButton.Content is FluentIcons.Avalonia.SymbolIcon refreshIcon)
{
refreshIcon.FontSize = iconSize;
}
if (GoButton.Content is FluentIcons.Avalonia.SymbolIcon goIcon)
{
goIcon.FontSize = iconSize;
}
AddressTextBox.FontSize = Math.Clamp(_currentCellSize * 0.30, 12, 15);
AddressTextBox.Height = buttonSize;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
ApplyTheme(force: true);
UpdateWebViewActiveState();
}
private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
_isOnActiveDesktopPage = false;
UpdateWebViewActiveState();
}
private void OnSizeChanged(object? sender, SizeChangedEventArgs e)
{
ApplyCellSize(_currentCellSize);
}
private void OnActualThemeVariantChanged(object? sender, EventArgs e)
{
ApplyTheme(force: false);
}
private void ApplyTheme(bool force)
{
var isNightMode = ResolveIsNightMode();
if (!force && _isNightModeApplied.HasValue && _isNightModeApplied.Value == isNightMode)
{
return;
}
_isNightModeApplied = isNightMode;
RootBorder.Background = new SolidColorBrush(isNightMode ? Color.Parse("#FF141A24") : Color.Parse("#FFF4F7FC"));
WebViewHostBorder.Background = new SolidColorBrush(isNightMode ? Color.Parse("#FF0A0E15") : Color.Parse("#FFFFFFFF"));
WebViewHostBorder.BorderBrush = new SolidColorBrush(isNightMode ? Color.Parse("#33FFFFFF") : Color.Parse("#22000000"));
AddressBarBorder.Background = new SolidColorBrush(isNightMode ? Color.Parse("#1BFFFFFF") : Color.Parse("#ECF2FA"));
AddressBarBorder.BorderBrush = new SolidColorBrush(isNightMode ? Color.Parse("#26FFFFFF") : Color.Parse("#22000000"));
var idleBackground = new SolidColorBrush(isNightMode ? Color.Parse("#24FFFFFF") : Color.Parse("#DCE6F5"));
var idleForeground = new SolidColorBrush(isNightMode ? Color.Parse("#FFE5E7EB") : Color.Parse("#FF1E293B"));
foreach (var button in new[] { RefreshButton, GoButton })
{
button.Background = idleBackground;
button.Foreground = idleForeground;
button.BorderThickness = new Thickness(0);
}
AddressTextBox.Background = new SolidColorBrush(isNightMode ? Color.Parse("#1F000000") : Color.Parse("#FFFFFFFF"));
AddressTextBox.BorderBrush = new SolidColorBrush(isNightMode ? Color.Parse("#2FFFFFFF") : Color.Parse("#22000000"));
AddressTextBox.Foreground = idleForeground;
AddressTextBox.CaretBrush = idleForeground;
}
private bool ResolveIsNightMode()
{
if (ActualThemeVariant == ThemeVariant.Dark)
{
return true;
}
if (ActualThemeVariant == ThemeVariant.Light)
{
return false;
}
if (this.TryFindResource("AdaptiveSurfaceBaseBrush", out var value) &&
value is ISolidColorBrush brush)
{
return CalculateRelativeLuminance(brush.Color) < 0.45;
}
return false;
}
private static double CalculateRelativeLuminance(Color color)
{
static double ToLinear(double channel)
{
return channel <= 0.03928
? channel / 12.92
: Math.Pow((channel + 0.055) / 1.055, 2.4);
}
var red = ToLinear(color.R / 255d);
var green = ToLinear(color.G / 255d);
var blue = ToLinear(color.B / 255d);
return (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
}
private void OnRefreshButtonClick(object? sender, RoutedEventArgs e)
{
if (!_isWebViewActive)
{
return;
}
if (BrowserWebView.Url is not null)
{
BrowserWebView.Reload();
return;
}
NavigateTo(DefaultHomeUri);
}
private void OnGoButtonClick(object? sender, RoutedEventArgs e)
{
NavigateFromAddressBar();
}
private void OnAddressTextBoxKeyDown(object? sender, KeyEventArgs e)
{
if (e.Key != Key.Enter)
{
return;
}
NavigateFromAddressBar();
e.Handled = true;
}
private void NavigateFromAddressBar()
{
var target = TryNormalizeUri(AddressTextBox.Text);
if (target is null)
{
return;
}
NavigateTo(target);
}
private void NavigateTo(Uri uri)
{
_lastKnownUri = uri;
AddressTextBox.Text = uri.ToString();
if (_isWebViewActive)
{
BrowserWebView.Url = uri;
}
}
private void OnBrowserWebViewNavigationStarting(object? sender, WebViewUrlLoadingEventArg e)
{
if (e.Url is null)
{
return;
}
_lastKnownUri = e.Url;
AddressTextBox.Text = e.Url.ToString();
}
public void SetDesktopPageContext(bool isOnActivePage, bool isEditMode)
{
_isOnActiveDesktopPage = isOnActivePage;
_isEditMode = isEditMode;
UpdateWebViewActiveState();
}
private void UpdateWebViewActiveState()
{
var shouldBeActive = _isOnActiveDesktopPage && !_isEditMode && IsVisible;
if (_isWebViewActive == shouldBeActive)
{
return;
}
_isWebViewActive = shouldBeActive;
if (!_isWebViewActive)
{
if (BrowserWebView.Url is Uri currentUri)
{
_lastKnownUri = currentUri;
}
BrowserWebView.IsHitTestVisible = false;
BrowserWebView.IsVisible = false;
BrowserWebView.Url = null;
return;
}
BrowserWebView.IsVisible = true;
BrowserWebView.IsHitTestVisible = true;
BrowserWebView.Url = _lastKnownUri;
}
private static Uri? TryNormalizeUri(string? rawText)
{
if (string.IsNullOrWhiteSpace(rawText))
{
return null;
}
var candidate = rawText.Trim();
if (!candidate.Contains("://", StringComparison.Ordinal))
{
candidate = $"https://{candidate}";
}
if (!Uri.TryCreate(candidate, UriKind.Absolute, out var uri))
{
return null;
}
return uri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) ||
uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)
? uri
: null;
}
}