251 lines
7.6 KiB
C#
251 lines
7.6 KiB
C#
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.Json;
|
|
using Microsoft.UI.Windowing;
|
|
using Microsoft.Web.WebView2.Core;
|
|
using MMoneyCoderSharp.Data;
|
|
using Windows.Graphics;
|
|
using Windows.System;
|
|
using WinRT.Interop;
|
|
|
|
namespace MBN_STOCK_WEBVIEW;
|
|
|
|
public sealed partial class MainWindow : Window
|
|
{
|
|
private const string AppHost = "app.mbn.local";
|
|
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
|
private bool _webViewReady;
|
|
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
Root.Loaded += OnRootLoaded;
|
|
Closed += OnClosed;
|
|
}
|
|
|
|
private async void OnRootLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
Root.Loaded -= OnRootLoaded;
|
|
ResizeWindow();
|
|
await InitializeWebViewAsync();
|
|
}
|
|
|
|
private void ResizeWindow()
|
|
{
|
|
try
|
|
{
|
|
var windowHandle = WindowNative.GetWindowHandle(this);
|
|
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
|
|
AppWindow.GetFromWindowId(windowId).Resize(new SizeInt32(1600, 960));
|
|
}
|
|
catch
|
|
{
|
|
// The system-selected size is still usable if sizing is unavailable.
|
|
}
|
|
}
|
|
|
|
private async Task InitializeWebViewAsync()
|
|
{
|
|
try
|
|
{
|
|
var webRoot = Path.Combine(AppContext.BaseDirectory, "Web");
|
|
var startPage = Path.Combine(webRoot, "index.html");
|
|
|
|
if (!File.Exists(startPage))
|
|
{
|
|
throw new FileNotFoundException("The packaged Web UI was not found.", startPage);
|
|
}
|
|
|
|
await Browser.EnsureCoreWebView2Async();
|
|
|
|
Browser.CoreWebView2.SetVirtualHostNameToFolderMapping(
|
|
AppHost,
|
|
webRoot,
|
|
CoreWebView2HostResourceAccessKind.DenyCors);
|
|
|
|
Browser.CoreWebView2.Settings.AreDevToolsEnabled = Debugger.IsAttached;
|
|
Browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = Debugger.IsAttached;
|
|
Browser.CoreWebView2.Settings.IsStatusBarEnabled = false;
|
|
|
|
Browser.CoreWebView2.NavigationStarting += OnNavigationStarting;
|
|
Browser.CoreWebView2.NavigationCompleted += OnNavigationCompleted;
|
|
Browser.CoreWebView2.HistoryChanged += OnHistoryChanged;
|
|
Browser.CoreWebView2.NewWindowRequested += OnNewWindowRequested;
|
|
Browser.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
|
|
Browser.CoreWebView2.ProcessFailed += OnProcessFailed;
|
|
|
|
_webViewReady = true;
|
|
Browser.Source = new Uri($"https://{AppHost}/index.html");
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ShowError("WebView2 초기화에 실패했습니다.", exception.Message);
|
|
}
|
|
}
|
|
|
|
private void OnNavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs args)
|
|
{
|
|
if (!Uri.TryCreate(args.Uri, UriKind.Absolute, out var uri))
|
|
{
|
|
args.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
if (uri.Host.Equals(AppHost, StringComparison.OrdinalIgnoreCase) || uri.Scheme == "about")
|
|
{
|
|
LoadingOverlay.Visibility = Visibility.Visible;
|
|
return;
|
|
}
|
|
|
|
args.Cancel = true;
|
|
_ = OpenExternalUriAsync(uri);
|
|
}
|
|
|
|
private void OnNavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs args)
|
|
{
|
|
LoadingOverlay.Visibility = Visibility.Collapsed;
|
|
|
|
if (!args.IsSuccess)
|
|
{
|
|
ShowError("운영 화면을 불러오지 못했습니다.", args.WebErrorStatus.ToString());
|
|
}
|
|
}
|
|
|
|
private void OnHistoryChanged(object? sender, object args)
|
|
{
|
|
BackButton.IsEnabled = Browser.CanGoBack;
|
|
ForwardButton.IsEnabled = Browser.CanGoForward;
|
|
}
|
|
|
|
private void OnNewWindowRequested(object? sender, CoreWebView2NewWindowRequestedEventArgs args)
|
|
{
|
|
args.Handled = true;
|
|
|
|
if (Uri.TryCreate(args.Uri, UriKind.Absolute, out var uri))
|
|
{
|
|
_ = OpenExternalUriAsync(uri);
|
|
}
|
|
}
|
|
|
|
private void OnWebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs args)
|
|
{
|
|
try
|
|
{
|
|
var request = JsonSerializer.Deserialize<WebRequest>(args.WebMessageAsJson, JsonOptions);
|
|
|
|
switch (request?.Type)
|
|
{
|
|
case "ready":
|
|
case "request-app-info":
|
|
PostAppInfo();
|
|
break;
|
|
case "open-external" when request.Payload.ValueKind == JsonValueKind.Object:
|
|
if (request.Payload.TryGetProperty("url", out var value) &&
|
|
Uri.TryCreate(value.GetString(), UriKind.Absolute, out var uri))
|
|
{
|
|
_ = OpenExternalUriAsync(uri);
|
|
}
|
|
break;
|
|
case "reload":
|
|
Browser.Reload();
|
|
break;
|
|
}
|
|
}
|
|
catch (JsonException exception)
|
|
{
|
|
PostMessage("bridge-error", new { message = exception.Message });
|
|
}
|
|
}
|
|
|
|
private void PostAppInfo()
|
|
{
|
|
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "1.0.0";
|
|
|
|
PostMessage("app-info", new
|
|
{
|
|
name = "MBN Stock WebView",
|
|
version,
|
|
framework = ".NET 8 / WinUI 3",
|
|
windowsAppSdk = "1.8",
|
|
architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(),
|
|
package = "MSIX",
|
|
migratedQueryFiles = 71,
|
|
databaseConfigured = DataQueryExecutor.IsConfigured
|
|
});
|
|
}
|
|
|
|
private void PostMessage(string type, object payload)
|
|
{
|
|
if (!_webViewReady)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Browser.CoreWebView2.PostWebMessageAsJson(
|
|
JsonSerializer.Serialize(new { type, payload }, JsonOptions));
|
|
}
|
|
|
|
private static async Task OpenExternalUriAsync(Uri uri)
|
|
{
|
|
if (uri.Scheme is "https" or "http")
|
|
{
|
|
await Launcher.LaunchUriAsync(uri);
|
|
}
|
|
}
|
|
|
|
private void OnProcessFailed(object? sender, CoreWebView2ProcessFailedEventArgs args)
|
|
{
|
|
ShowError("WebView2 프로세스가 종료되었습니다.", args.ProcessFailedKind.ToString());
|
|
}
|
|
|
|
private void ShowError(string title, string message)
|
|
{
|
|
LoadingOverlay.Visibility = Visibility.Collapsed;
|
|
ErrorBar.Title = title;
|
|
ErrorBar.Message = message;
|
|
ErrorBar.IsOpen = true;
|
|
}
|
|
|
|
private void OnBackClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
if (Browser.CanGoBack)
|
|
{
|
|
Browser.GoBack();
|
|
}
|
|
}
|
|
|
|
private void OnForwardClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
if (Browser.CanGoForward)
|
|
{
|
|
Browser.GoForward();
|
|
}
|
|
}
|
|
|
|
private void OnReloadClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_webViewReady)
|
|
{
|
|
Browser.Reload();
|
|
}
|
|
}
|
|
|
|
private void OnClosed(object sender, WindowEventArgs args)
|
|
{
|
|
if (!_webViewReady)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Browser.CoreWebView2.NavigationStarting -= OnNavigationStarting;
|
|
Browser.CoreWebView2.NavigationCompleted -= OnNavigationCompleted;
|
|
Browser.CoreWebView2.HistoryChanged -= OnHistoryChanged;
|
|
Browser.CoreWebView2.NewWindowRequested -= OnNewWindowRequested;
|
|
Browser.CoreWebView2.WebMessageReceived -= OnWebMessageReceived;
|
|
Browser.CoreWebView2.ProcessFailed -= OnProcessFailed;
|
|
}
|
|
|
|
private sealed record WebRequest(string Type, JsonElement Payload);
|
|
}
|