[Peek] add WV2 improvements (behavior and UX) (#22685)

* [Peek] added logic to get max monitor size for opening WebView2

* Removed ununsed dependency property

* Added workaround for cases where the web page would not finish navigating in a quick timing, for example google.com.

* Remove window extensions from common and use nullable size argument instead

Co-authored-by: Samuel Chapleau <sachaple@microsoft.com>
This commit is contained in:
Robson 2022-12-13 21:37:17 -08:00 committed by GitHub
parent 1253ed6607
commit c22e78870b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 66 additions and 30 deletions

View File

@ -10,7 +10,7 @@ namespace Peek.FilePreviewer.Controls
using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Core;
using Windows.System; using Windows.System;
public sealed partial class BrowserControl : UserControl public sealed partial class BrowserControl : UserControl, IDisposable
{ {
/// <summary> /// <summary>
/// Helper private Uri where we cache the last navigated page /// Helper private Uri where we cache the last navigated page
@ -21,37 +21,37 @@ namespace Peek.FilePreviewer.Controls
public delegate void NavigationCompletedHandler(WebView2? sender, CoreWebView2NavigationCompletedEventArgs? args); public delegate void NavigationCompletedHandler(WebView2? sender, CoreWebView2NavigationCompletedEventArgs? args);
public delegate void DOMContentLoadedHandler(CoreWebView2? sender, CoreWebView2DOMContentLoadedEventArgs? args);
public event NavigationCompletedHandler? NavigationCompleted; public event NavigationCompletedHandler? NavigationCompleted;
public event DOMContentLoadedHandler? DOMContentLoaded;
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
nameof(Source), nameof(Source),
typeof(Uri), typeof(Uri),
typeof(BrowserControl), typeof(BrowserControl),
new PropertyMetadata(null, new PropertyChangedCallback((d, e) => ((BrowserControl)d).SourcePropertyChanged()))); new PropertyMetadata(null, new PropertyChangedCallback((d, e) => ((BrowserControl)d).SourcePropertyChanged())));
public static readonly DependencyProperty IsNavigationCompletedProperty = DependencyProperty.Register(
nameof(IsNavigationCompleted),
typeof(bool),
typeof(BrowserControl),
new PropertyMetadata(false));
public Uri? Source public Uri? Source
{ {
get { return (Uri)GetValue(SourceProperty); } get { return (Uri)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); } set { SetValue(SourceProperty, value); }
} }
public bool IsNavigationCompleted
{
get { return (bool)GetValue(IsNavigationCompletedProperty); }
set { SetValue(IsNavigationCompletedProperty, value); }
}
public BrowserControl() public BrowserControl()
{ {
this.InitializeComponent(); this.InitializeComponent();
} }
public void Dispose()
{
if (PreviewBrowser.CoreWebView2 != null)
{
PreviewBrowser.CoreWebView2.DOMContentLoaded -= CoreWebView2_DOMContentLoaded;
}
}
/// <summary> /// <summary>
/// Navigate to the to the <see cref="Uri"/> set in <see cref="Source"/>. /// Navigate to the to the <see cref="Uri"/> set in <see cref="Source"/>.
/// Calling <see cref="Navigate"/> will always trigger a navigation/refresh /// Calling <see cref="Navigate"/> will always trigger a navigation/refresh
@ -59,7 +59,8 @@ namespace Peek.FilePreviewer.Controls
/// </summary> /// </summary>
public void Navigate() public void Navigate()
{ {
IsNavigationCompleted = false; var value = Environment.GetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS");
_navigatedUri = null; _navigatedUri = null;
if (Source != null) if (Source != null)
@ -89,6 +90,8 @@ namespace Peek.FilePreviewer.Controls
PreviewBrowser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false; PreviewBrowser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
PreviewBrowser.CoreWebView2.Settings.IsScriptEnabled = false; PreviewBrowser.CoreWebView2.Settings.IsScriptEnabled = false;
PreviewBrowser.CoreWebView2.Settings.IsWebMessageEnabled = false; PreviewBrowser.CoreWebView2.Settings.IsWebMessageEnabled = false;
PreviewBrowser.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
} }
catch catch
{ {
@ -96,6 +99,11 @@ namespace Peek.FilePreviewer.Controls
} }
} }
private void CoreWebView2_DOMContentLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args)
{
DOMContentLoaded?.Invoke(sender, args);
}
private async void PreviewBrowser_NavigationStarting(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs args) private async void PreviewBrowser_NavigationStarting(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs args)
{ {
if (_navigatedUri == null) if (_navigatedUri == null)
@ -115,8 +123,6 @@ namespace Peek.FilePreviewer.Controls
{ {
if (args.IsSuccess) if (args.IsSuccess)
{ {
IsNavigationCompleted = true;
_navigatedUri = Source; _navigatedUri = Source;
} }

View File

@ -28,6 +28,7 @@
x:Name="BrowserPreview" x:Name="BrowserPreview"
x:Load="True" x:Load="True"
NavigationCompleted="PreviewBrowser_NavigationCompleted" NavigationCompleted="PreviewBrowser_NavigationCompleted"
DOMContentLoaded="BrowserPreview_DOMContentLoaded"
Source="{x:Bind BrowserPreviewer.Preview, Mode=OneWay}" Source="{x:Bind BrowserPreviewer.Preview, Mode=OneWay}"
Visibility="{x:Bind IsPreviewVisible(BrowserPreviewer, Previewer.State), Mode=OneWay, FallbackValue=Collapsed}" /> Visibility="{x:Bind IsPreviewVisible(BrowserPreviewer, Previewer.State), Mode=OneWay, FallbackValue=Collapsed}" />

View File

@ -153,15 +153,43 @@ namespace Peek.FilePreviewer
} }
} }
private void PreviewBrowser_NavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args) private void BrowserPreview_DOMContentLoaded(Microsoft.Web.WebView2.Core.CoreWebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2DOMContentLoadedEventArgs args)
{ {
// Once browser has completed navigation it is ready to be visible /*
* There is an odd behavior where the WebView2 would not raise the NavigationCompleted event
* for certain HTML files, even though it has already been loaded. Probably related to certain
* extra module that require more time to load. One example is saving and opening google.com locally.
*
* So to address this, we will make the Browser visible and display it as "Loaded" as soon the HTML document
* has been parsed and loaded with the DOMContentLoaded event.
*
* Similar issue: https://github.com/MicrosoftEdge/WebView2Feedback/issues/998
*/
if (BrowserPreviewer != null) if (BrowserPreviewer != null)
{ {
BrowserPreviewer.State = PreviewState.Loaded; BrowserPreviewer.State = PreviewState.Loaded;
} }
} }
private void PreviewBrowser_NavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
{
/*
* In theory most of navigation should work after DOM is loaded.
* But in case something fails we check NavigationCompleted event
* for failure and switch visibility accordingly.
*
* As an alternative, in the future, the preview Browser control
* could also display error content.
*/
if (!args.IsSuccess)
{
if (BrowserPreviewer != null)
{
BrowserPreviewer.State = PreviewState.Error;
}
}
}
private async void KeyboardAccelerator_CtrlC_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) private async void KeyboardAccelerator_CtrlC_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{ {
if (Previewer != null) if (Previewer != null)

View File

@ -14,13 +14,13 @@ namespace Peek.FilePreviewer.Models
public class PreviewSizeChangedArgs public class PreviewSizeChangedArgs
{ {
public PreviewSizeChangedArgs(Size windowSizeRequested, SizeFormat sizeFormat = SizeFormat.Pixels) public PreviewSizeChangedArgs(Size? windowSizeRequested, SizeFormat sizeFormat = SizeFormat.Pixels)
{ {
WindowSizeRequested = windowSizeRequested; WindowSizeRequested = windowSizeRequested;
WindowSizeFormat = sizeFormat; WindowSizeFormat = sizeFormat;
} }
public Size WindowSizeRequested { get; init; } public Size? WindowSizeRequested { get; init; }
public SizeFormat WindowSizeFormat { get; init; } public SizeFormat WindowSizeFormat { get; init; }
} }

View File

@ -16,7 +16,7 @@ namespace Peek.FilePreviewer.Previewers
public static bool IsFileTypeSupported(string fileExt) => throw new NotImplementedException(); public static bool IsFileTypeSupported(string fileExt) => throw new NotImplementedException();
public Task<Size> GetPreviewSizeAsync(CancellationToken cancellationToken); public Task<Size?> GetPreviewSizeAsync(CancellationToken cancellationToken);
Task LoadPreviewAsync(CancellationToken cancellationToken); Task LoadPreviewAsync(CancellationToken cancellationToken);

View File

@ -57,7 +57,7 @@ namespace Peek.FilePreviewer.Previewers
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public async Task<Size> GetPreviewSizeAsync(CancellationToken cancellationToken) public async Task<Size?> GetPreviewSizeAsync(CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var propertyImageSize = await PropertyHelper.GetImageSize(File.Path); var propertyImageSize = await PropertyHelper.GetImageSize(File.Path);

View File

@ -56,7 +56,7 @@ namespace Peek.FilePreviewer.Previewers
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public async Task<Size> GetPreviewSizeAsync(CancellationToken cancellationToken) public async Task<Size?> GetPreviewSizeAsync(CancellationToken cancellationToken)
{ {
var propertyImageSize = await PropertyHelper.GetImageSize(File.Path); var propertyImageSize = await PropertyHelper.GetImageSize(File.Path);
if (propertyImageSize != Size.Empty) if (propertyImageSize != Size.Empty)

View File

@ -80,11 +80,12 @@ namespace Peek.FilePreviewer.Previewers
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public Task<Size> GetPreviewSizeAsync(CancellationToken cancellationToken) public Task<Size?> GetPreviewSizeAsync(CancellationToken cancellationToken)
{ {
return Task.Run(() => return Task.Run(() =>
{ {
return new Size(UnsupportedFileWidthPercent, UnsupportedFileHeightPercent); Size? size = new Size(UnsupportedFileWidthPercent, UnsupportedFileHeightPercent);
return size;
}); });
} }

View File

@ -45,10 +45,9 @@ namespace Peek.FilePreviewer.Previewers
private DispatcherQueue Dispatcher { get; } private DispatcherQueue Dispatcher { get; }
public Task<Size> GetPreviewSizeAsync(CancellationToken cancellationToken) public Task<Size?> GetPreviewSizeAsync(CancellationToken cancellationToken)
{ {
// TODO: define how to proper window size on HTML content. Size? size = null;
var size = new Size(1280, 720);
return Task.FromResult(size); return Task.FromResult(size);
} }

View File

@ -94,10 +94,11 @@ namespace Peek.UI
/// <param name="e">PreviewSizeChangedArgs</param> /// <param name="e">PreviewSizeChangedArgs</param>
private void FilePreviewer_PreviewSizeChanged(object sender, PreviewSizeChangedArgs e) private void FilePreviewer_PreviewSizeChanged(object sender, PreviewSizeChangedArgs e)
{ {
// TODO: Use design-defined rules for adjusted window size
var requestedSize = e.WindowSizeRequested;
var monitorSize = this.GetMonitorSize(); var monitorSize = this.GetMonitorSize();
// If no size is requested, try to fit to the monitor size.
Size requestedSize = e.WindowSizeRequested ?? monitorSize;
var titleBarHeight = TitleBarControl.ActualHeight; var titleBarHeight = TitleBarControl.ActualHeight;
var maxContentSize = new Size(0, 0); var maxContentSize = new Size(0, 0);