From fa238a09150d17f6da5b4850f44690d15859e79e Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Mon, 3 Nov 2025 09:35:12 -0700 Subject: [PATCH] Use xplat webview control for Audible login - Use Avalonia-based webview control for Audible login with Chardonnay - Remove webview interfaces from IInteropFunctions - Remove Microsoft.Web.WebView2 package from WindowsConfigApp - Add Microsoft.Web.WebView2 to LibationWinForms - Remove all other login forms except the external login dialog (fallback in case webview doesn't work). The AudibleApi login with username/password doesn't work anymore. Need to use external browser login method. --- Scripts/Bundle_Debian.sh | 1 + Scripts/Bundle_Redhat.sh | 2 +- Source/LibationAvalonia/AvaloniaUtils.cs | 5 - .../Controls/NativeWebView.cs | 176 ------------------ .../Dialogs/Login/ApprovalNeededDialog.axaml | 34 ---- .../Login/ApprovalNeededDialog.axaml.cs | 22 --- .../Dialogs/Login/AvaloniaLoginCallback.cs | 60 +----- .../Dialogs/Login/AvaloniaLoginChoiceEager.cs | 101 +++++++--- .../Dialogs/Login/CaptchaDialog.axaml | 72 ------- .../Dialogs/Login/CaptchaDialog.axaml.cs | 120 ------------ .../Dialogs/Login/LoginCallbackDialog.axaml | 38 ---- .../Login/LoginCallbackDialog.axaml.cs | 42 ----- .../Login/LoginChoiceEagerDialog.axaml | 70 ------- .../Login/LoginChoiceEagerDialog.axaml.cs | 50 ----- .../Dialogs/Login/MfaDialog.axaml | 19 -- .../Dialogs/Login/MfaDialog.axaml.cs | 137 -------------- .../Dialogs/Login/WebLoginDialog.axaml | 12 -- .../Dialogs/Login/WebLoginDialog.axaml.cs | 55 ------ .../Dialogs/Login/_2faCodeDialog.axaml | 44 ----- .../Dialogs/Login/_2faCodeDialog.axaml.cs | 35 ---- .../LibationAvalonia/LibationAvalonia.csproj | 4 +- .../LibationFileManager/IInteropFunctions.cs | 39 ---- .../NullInteropFunctions.cs | 1 - .../Login/ApprovalNeededDialog.Designer.cs | 83 --------- .../Dialogs/Login/ApprovalNeededDialog.cs | 21 --- .../Dialogs/Login/ApprovalNeededDialog.resx | 61 ------ .../Dialogs/Login/CaptchaDialog.Designer.cs | 131 ------------- .../Dialogs/Login/CaptchaDialog.cs | 48 ----- .../Dialogs/Login/CaptchaDialog.resx | 61 ------ .../Login/LoginCallbackDialog.Designer.cs | 121 ------------ .../Dialogs/Login/LoginCallbackDialog.cs | 37 ---- .../Dialogs/Login/LoginCallbackDialog.resx | 60 ------ .../Login/LoginChoiceEagerDialog.Designer.cs | 158 ---------------- .../Dialogs/Login/LoginChoiceEagerDialog.cs | 53 ------ .../Dialogs/Login/LoginChoiceEagerDialog.resx | 60 ------ .../Dialogs/Login/MfaDialog.Designer.cs | 113 ----------- .../Dialogs/Login/MfaDialog.cs | 92 --------- .../Dialogs/Login/MfaDialog.resx | 61 ------ .../Dialogs/Login/WebLoginDialog.cs | 48 ++--- .../Dialogs/Login/WinformLoginBase.cs | 23 --- .../Dialogs/Login/WinformLoginCallback.cs | 54 +----- .../Dialogs/Login/WinformLoginChoiceEager.cs | 44 ++--- .../Dialogs/Login/_2faCodeDialog.Designer.cs | 104 ----------- .../Dialogs/Login/_2faCodeDialog.cs | 26 --- .../Dialogs/Login/_2faCodeDialog.resx | 61 ------ .../LibationWinForms/LibationWinForms.csproj | 3 +- .../LoadByOS/LinuxConfigApp/Libation.desktop | 2 +- .../LoadByOS/LinuxConfigApp/LinuxInterop.cs | 1 - .../LoadByOS/MacOSConfigApp/MacOSInterop.cs | 1 - .../MacOSConfigApp/MacWebViewAdapter.cs | 134 ------------- .../LoadByOS/WindowsConfigApp/WinInterop.cs | 4 - .../WindowsConfigApp/WindowsConfigApp.csproj | 5 - .../WindowsWebView2Adapter.cs | 114 ------------ 53 files changed, 137 insertions(+), 2786 deletions(-) delete mode 100644 Source/LibationAvalonia/Controls/NativeWebView.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/ApprovalNeededDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/ApprovalNeededDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/CaptchaDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/CaptchaDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/LoginCallbackDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/LoginCallbackDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/MfaDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/WebLoginDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/WebLoginDialog.axaml.cs delete mode 100644 Source/LibationAvalonia/Dialogs/Login/_2faCodeDialog.axaml delete mode 100644 Source/LibationAvalonia/Dialogs/Login/_2faCodeDialog.axaml.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/ApprovalNeededDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/ApprovalNeededDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/ApprovalNeededDialog.resx delete mode 100644 Source/LibationWinForms/Dialogs/Login/CaptchaDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/CaptchaDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/CaptchaDialog.resx delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginCallbackDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginCallbackDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginCallbackDialog.resx delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginChoiceEagerDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginChoiceEagerDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/LoginChoiceEagerDialog.resx delete mode 100644 Source/LibationWinForms/Dialogs/Login/MfaDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/MfaDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/MfaDialog.resx delete mode 100644 Source/LibationWinForms/Dialogs/Login/WinformLoginBase.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/_2faCodeDialog.Designer.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/_2faCodeDialog.cs delete mode 100644 Source/LibationWinForms/Dialogs/Login/_2faCodeDialog.resx delete mode 100644 Source/LoadByOS/MacOSConfigApp/MacWebViewAdapter.cs delete mode 100644 Source/LoadByOS/WindowsConfigApp/WindowsWebView2Adapter.cs diff --git a/Scripts/Bundle_Debian.sh b/Scripts/Bundle_Debian.sh index 3ca7ef13..b69eb76f 100644 --- a/Scripts/Bundle_Debian.sh +++ b/Scripts/Bundle_Debian.sh @@ -113,6 +113,7 @@ Essential: no Priority: optional Maintainer: github.com/rmcrackan Description: liberate your audiobooks +Recommends: libgtk-3-0, libwebkit2gtk-4.1-0 " >> $FOLDER_DEBIAN/control echo "Changing permissions for pre- and post-install files..." diff --git a/Scripts/Bundle_Redhat.sh b/Scripts/Bundle_Redhat.sh index 1b18f1d1..05d27ac6 100644 --- a/Scripts/Bundle_Redhat.sh +++ b/Scripts/Bundle_Redhat.sh @@ -62,7 +62,7 @@ License: GPLv3+ URL: https://github.com/rmcrackan/Libation Source0: https://github.com/rmcrackan/Libation -Requires: bash +Requires: bash gtk3 webkit2gtk4.1 %define __os_install_post %{nil} diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 4bfc1aa7..82a360ba 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -23,11 +23,6 @@ namespace LibationAvalonia ? dialogWindow.ShowDialog(window) : Task.FromResult(DialogResult.None); - public static Task ShowDialogAsync(this Dialogs.Login.WebLoginDialog dialogWindow, Window? owner = null) - => ((owner ?? App.MainWindow) is Window window) - ? dialogWindow.ShowDialog(window) - : Task.FromResult(DialogResult.None); - public static Window? GetParentWindow(this Control control) => control.GetVisualRoot() as Window; diff --git a/Source/LibationAvalonia/Controls/NativeWebView.cs b/Source/LibationAvalonia/Controls/NativeWebView.cs deleted file mode 100644 index 0aad165d..00000000 --- a/Source/LibationAvalonia/Controls/NativeWebView.cs +++ /dev/null @@ -1,176 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Platform; -using Avalonia; -using LibationFileManager; -using System; -using System.Threading.Tasks; - -namespace LibationAvalonia.Controls; - -#nullable enable -public class NativeWebView : NativeControlHost, IWebView -{ - private IWebViewAdapter? _webViewAdapter; - private Uri? _delayedSource; - private TaskCompletionSource _webViewReadyCompletion = new(); - - public event EventHandler? NavigationCompleted; - - public event EventHandler? NavigationStarted; - public event EventHandler? DOMContentLoaded; - - public bool CanGoBack => _webViewAdapter?.CanGoBack ?? false; - - public bool CanGoForward => _webViewAdapter?.CanGoForward ?? false; - - public Uri? Source - { - get => _webViewAdapter?.Source ?? throw new InvalidOperationException("Control was not initialized"); - set - { - if (_webViewAdapter is null) - { - _delayedSource = value; - return; - } - _webViewAdapter.Source = value; - } - } - - - public bool GoBack() - { - return _webViewAdapter?.GoBack() ?? throw new InvalidOperationException("Control was not initialized"); - } - - public bool GoForward() - { - return _webViewAdapter?.GoForward() ?? throw new InvalidOperationException("Control was not initialized"); - } - - public Task InvokeScriptAsync(string scriptName) - { - return _webViewAdapter is null - ? throw new InvalidOperationException("Control was not initialized") - : _webViewAdapter.InvokeScriptAsync(scriptName); - } - - public void Navigate(Uri url) - { - (_webViewAdapter ?? throw new InvalidOperationException("Control was not initialized")) - .Navigate(url); - } - - public Task NavigateToString(string text) - { - return (_webViewAdapter ?? throw new InvalidOperationException("Control was not initialized")) - .NavigateToString(text); - } - - public void Refresh() - { - (_webViewAdapter ?? throw new InvalidOperationException("Control was not initialized")) - .Refresh(); - } - - public void Stop() - { - (_webViewAdapter ?? throw new InvalidOperationException("Control was not initialized")) - .Stop(); - } - - public Task WaitForNativeHost() - { - return _webViewReadyCompletion.Task; - } - - private class PlatformHandle : IPlatformHandle - { - public nint Handle { get; init; } - - public string? HandleDescriptor { get; init; } - } - - protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent) - { - _webViewAdapter = InteropFactory.Create().CreateWebViewAdapter(); - - if (_webViewAdapter is null) - return base.CreateNativeControlCore(parent); - else - { - SubscribeOnEvents(); - var handle = new PlatformHandle - { - Handle = _webViewAdapter.PlatformHandle.Handle, - HandleDescriptor = _webViewAdapter.PlatformHandle.HandleDescriptor - }; - - if (_delayedSource is not null) - { - _webViewAdapter.Source = _delayedSource; - } - - _webViewReadyCompletion.TrySetResult(); - - return handle; - } - } - - private void SubscribeOnEvents() - { - if (_webViewAdapter is not null) - { - _webViewAdapter.NavigationStarted += WebViewAdapterOnNavigationStarted; - _webViewAdapter.NavigationCompleted += WebViewAdapterOnNavigationCompleted; - _webViewAdapter.DOMContentLoaded += _webViewAdapter_DOMContentLoaded; - } - } - - private void _webViewAdapter_DOMContentLoaded(object? sender, EventArgs e) - { - DOMContentLoaded?.Invoke(this, e); - } - - private void WebViewAdapterOnNavigationStarted(object? sender, WebViewNavigationEventArgs e) - { - NavigationStarted?.Invoke(this, e); - } - - private void WebViewAdapterOnNavigationCompleted(object? sender, WebViewNavigationEventArgs e) - { - NavigationCompleted?.Invoke(this, e); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - if (change.Property == BoundsProperty && change.NewValue is Rect rect) - { - var scaling = (float)(VisualRoot?.RenderScaling ?? 1.0f); - _webViewAdapter?.HandleResize((int)(rect.Width * scaling), (int)(rect.Height * scaling), scaling); - } - } - - protected override void OnKeyDown(KeyEventArgs e) - { - if (_webViewAdapter != null) - { - e.Handled = _webViewAdapter.HandleKeyDown((uint)e.Key, (uint)e.KeyModifiers); - } - - base.OnKeyDown(e); - } - - protected override void DestroyNativeControlCore(IPlatformHandle control) - { - if (_webViewAdapter is not null) - { - _webViewReadyCompletion = new TaskCompletionSource(); - _webViewAdapter.NavigationStarted -= WebViewAdapterOnNavigationStarted; - _webViewAdapter.NavigationCompleted -= WebViewAdapterOnNavigationCompleted; - (_webViewAdapter as IDisposable)?.Dispose(); - } - } -} diff --git a/Source/LibationAvalonia/Dialogs/Login/ApprovalNeededDialog.axaml b/Source/LibationAvalonia/Dialogs/Login/ApprovalNeededDialog.axaml deleted file mode 100644 index 8d52c43c..00000000 --- a/Source/LibationAvalonia/Dialogs/Login/ApprovalNeededDialog.axaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - -