mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
292 lines
8.8 KiB
C#
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;
|
|
}
|
|
}
|