mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-23 03:15:48 +02:00
Move CEF dialog logic into library projects
This commit is contained in:
parent
45a3a7499f
commit
b815ae4b11
lib/TweetLib.Browser.CEF
Dialogs
Interfaces
Logic
windows
7
lib/TweetLib.Browser.CEF/Dialogs/FileDialogType.cs
Normal file
7
lib/TweetLib.Browser.CEF/Dialogs/FileDialogType.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace TweetLib.Browser.CEF.Dialogs {
|
||||
public enum FileDialogType {
|
||||
Open,
|
||||
OpenMultiple,
|
||||
Other
|
||||
}
|
||||
}
|
8
lib/TweetLib.Browser.CEF/Dialogs/JsDialogType.cs
Normal file
8
lib/TweetLib.Browser.CEF/Dialogs/JsDialogType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace TweetLib.Browser.CEF.Dialogs {
|
||||
public enum JsDialogType {
|
||||
Alert,
|
||||
Confirm,
|
||||
Prompt,
|
||||
Unknown
|
||||
}
|
||||
}
|
9
lib/TweetLib.Browser.CEF/Dialogs/MessageDialogType.cs
Normal file
9
lib/TweetLib.Browser.CEF/Dialogs/MessageDialogType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace TweetLib.Browser.CEF.Dialogs {
|
||||
public enum MessageDialogType {
|
||||
None,
|
||||
Question,
|
||||
Information,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace TweetLib.Browser.CEF.Interfaces {
|
||||
public interface IFileDialogCallbackAdapter<T> {
|
||||
void Continue(T callback, int selectedAcceptFilter, string[] filePaths);
|
||||
void Cancel(T callback);
|
||||
void Dispose(T callback);
|
||||
}
|
||||
}
|
8
lib/TweetLib.Browser.CEF/Interfaces/IFileDialogOpener.cs
Normal file
8
lib/TweetLib.Browser.CEF/Interfaces/IFileDialogOpener.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TweetLib.Browser.CEF.Interfaces {
|
||||
public interface IFileDialogOpener {
|
||||
void OpenFile(string title, bool multiple, List<string> supportedExtensions, Action<string[]> onAccepted, Action onCancelled);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace TweetLib.Browser.CEF.Interfaces {
|
||||
public interface IJsDialogCallbackAdapter<T> {
|
||||
void Continue(T callback, bool success, string? userInput = null);
|
||||
void Dispose(T callback);
|
||||
}
|
||||
}
|
10
lib/TweetLib.Browser.CEF/Interfaces/IJsDialogOpener.cs
Normal file
10
lib/TweetLib.Browser.CEF/Interfaces/IJsDialogOpener.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
|
||||
namespace TweetLib.Browser.CEF.Interfaces {
|
||||
public interface IJsDialogOpener {
|
||||
void Alert(MessageDialogType type, string title, string message, Action<bool> callback);
|
||||
void Confirm(MessageDialogType type, string title, string message, Action<bool> callback);
|
||||
void Prompt(MessageDialogType type, string title, string message, Action<bool, string> callback);
|
||||
}
|
||||
}
|
68
lib/TweetLib.Browser.CEF/Logic/DialogHandlerLogic.cs
Normal file
68
lib/TweetLib.Browser.CEF/Logic/DialogHandlerLogic.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
using TweetLib.Utils.Static;
|
||||
|
||||
namespace TweetLib.Browser.CEF.Logic {
|
||||
public sealed class DialogHandlerLogic<TCallback> {
|
||||
private readonly IFileDialogOpener fileDialogOpener;
|
||||
private readonly IFileDialogCallbackAdapter<TCallback> callbackAdapter;
|
||||
|
||||
public DialogHandlerLogic(IFileDialogOpener fileDialogOpener, IFileDialogCallbackAdapter<TCallback> callbackAdapter) {
|
||||
this.fileDialogOpener = fileDialogOpener;
|
||||
this.callbackAdapter = callbackAdapter;
|
||||
}
|
||||
|
||||
public bool OnFileDialog(FileDialogType type, IEnumerable<string> acceptFilters, TCallback callback) {
|
||||
if (type is FileDialogType.Open or FileDialogType.OpenMultiple) {
|
||||
var multiple = type == FileDialogType.OpenMultiple;
|
||||
var supportedExtensions = acceptFilters.SelectMany(ParseFileType).Where(static filter => !string.IsNullOrEmpty(filter)).ToList();
|
||||
|
||||
fileDialogOpener.OpenFile("Open Files", multiple, supportedExtensions, files => {
|
||||
string ext = Path.GetExtension(files[0])!.ToLower();
|
||||
callbackAdapter.Continue(callback, supportedExtensions.FindIndex(filter => ParseFileType(filter).Contains(ext)), files);
|
||||
callbackAdapter.Dispose(callback);
|
||||
}, () => {
|
||||
callbackAdapter.Cancel(callback);
|
||||
callbackAdapter.Dispose(callback);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
callbackAdapter.Dispose(callback);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> ParseFileType(string type) {
|
||||
if (string.IsNullOrEmpty(type)) {
|
||||
return StringUtils.EmptyArray;
|
||||
}
|
||||
|
||||
if (type[0] == '.') {
|
||||
return new string[] { type };
|
||||
}
|
||||
|
||||
string[] extensions = type switch {
|
||||
"image/jpeg" => new string[] { ".jpg", ".jpeg" },
|
||||
"image/png" => new string[] { ".png" },
|
||||
"image/gif" => new string[] { ".gif" },
|
||||
"image/webp" => new string[] { ".webp" },
|
||||
"video/mp4" => new string[] { ".mp4" },
|
||||
"video/quicktime" => new string[] { ".mov", ".qt" },
|
||||
_ => StringUtils.EmptyArray
|
||||
};
|
||||
|
||||
if (extensions.Length == 0) {
|
||||
Debug.WriteLine("Unknown file type: " + type);
|
||||
Debugger.Break();
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
}
|
||||
}
|
71
lib/TweetLib.Browser.CEF/Logic/JsDialogHandlerLogic.cs
Normal file
71
lib/TweetLib.Browser.CEF/Logic/JsDialogHandlerLogic.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
|
||||
namespace TweetLib.Browser.CEF.Logic {
|
||||
public sealed class JsDialogHandlerLogic<TCallback> {
|
||||
private static (MessageDialogType, string) GetMessageDialogProperties(string text) {
|
||||
MessageDialogType type = MessageDialogType.None;
|
||||
|
||||
int pipe = text.IndexOf('|');
|
||||
if (pipe != -1) {
|
||||
type = text.Substring(0, pipe) switch {
|
||||
"error" => MessageDialogType.Error,
|
||||
"warning" => MessageDialogType.Warning,
|
||||
"info" => MessageDialogType.Information,
|
||||
"question" => MessageDialogType.Question,
|
||||
_ => MessageDialogType.None
|
||||
};
|
||||
|
||||
if (type != MessageDialogType.None) {
|
||||
text = text.Substring(pipe + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (type, text);
|
||||
}
|
||||
|
||||
private readonly IJsDialogOpener jsDialogOpener;
|
||||
private readonly IJsDialogCallbackAdapter<TCallback> callbackAdapter;
|
||||
|
||||
public JsDialogHandlerLogic(IJsDialogOpener jsDialogOpener, IJsDialogCallbackAdapter<TCallback> callbackAdapter) {
|
||||
this.jsDialogOpener = jsDialogOpener;
|
||||
this.callbackAdapter = callbackAdapter;
|
||||
}
|
||||
|
||||
public bool OnJSDialog(JsDialogType dialogType, string messageText, TCallback callback, out bool suppressMessage) {
|
||||
suppressMessage = false;
|
||||
|
||||
var (type, text) = GetMessageDialogProperties(messageText);
|
||||
|
||||
if (dialogType == JsDialogType.Alert) {
|
||||
jsDialogOpener.Alert(type, "Browser Message", text, success => {
|
||||
callbackAdapter.Continue(callback, success);
|
||||
callbackAdapter.Dispose(callback);
|
||||
});
|
||||
}
|
||||
else if (dialogType == JsDialogType.Confirm) {
|
||||
jsDialogOpener.Confirm(type, "Browser Confirmation", text, success => {
|
||||
callbackAdapter.Continue(callback, success);
|
||||
callbackAdapter.Dispose(callback);
|
||||
});
|
||||
}
|
||||
else if (dialogType == JsDialogType.Prompt) {
|
||||
jsDialogOpener.Prompt(type, "Browser Prompt", text, (success, input) => {
|
||||
callbackAdapter.Continue(callback, success, input);
|
||||
callbackAdapter.Dispose(callback);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnBeforeUnloadDialog(IDisposable callback) {
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using CefSharp.WinForms;
|
||||
using TweetDuck.Utils;
|
||||
using TweetImpl.CefSharp.Component;
|
||||
using TweetLib.Browser.Base;
|
||||
using TweetLib.Browser.CEF.Utils;
|
||||
using TweetLib.Core;
|
||||
|
||||
@ -11,13 +10,8 @@ sealed class CefBrowserComponent : BrowserComponentBase {
|
||||
|
||||
public override string CacheFolder => CefUtils.GetCacheFolder(App.StoragePath);
|
||||
|
||||
public CefBrowserComponent(ChromiumWebBrowser browser, CreateContextMenu createContextMenu = null, bool autoReload = true) : base(browser, createContextMenu ?? DefaultContextMenuFactory, PopupHandler.Instance, autoReload) {
|
||||
public CefBrowserComponent(ChromiumWebBrowser browser, CreateContextMenu createContextMenu = null, bool autoReload = true) : base(browser, createContextMenu ?? DefaultContextMenuFactory, new JsDialogOpener(browser), PopupHandler.Instance, autoReload) {
|
||||
browser.SetupZoomEvents();
|
||||
}
|
||||
|
||||
public override void Setup(BrowserSetup setup) {
|
||||
base.Setup(setup);
|
||||
browser.JsDialogHandler = new CustomJsDialogHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,97 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using TweetDuck.Controls;
|
||||
using TweetDuck.Dialogs;
|
||||
using TweetDuck.Utils;
|
||||
|
||||
namespace TweetDuck.Browser.Base {
|
||||
sealed class CustomJsDialogHandler : IJsDialogHandler {
|
||||
private static FormMessage CreateMessageForm(string caption, string text) {
|
||||
MessageBoxIcon icon = MessageBoxIcon.None;
|
||||
int pipe = text.IndexOf('|');
|
||||
|
||||
if (pipe != -1) {
|
||||
icon = text.Substring(0, pipe) switch {
|
||||
"error" => MessageBoxIcon.Error,
|
||||
"warning" => MessageBoxIcon.Warning,
|
||||
"info" => MessageBoxIcon.Information,
|
||||
"question" => MessageBoxIcon.Question,
|
||||
_ => MessageBoxIcon.None
|
||||
};
|
||||
|
||||
if (icon != MessageBoxIcon.None) {
|
||||
text = text.Substring(pipe + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return new FormMessage(caption, text, icon);
|
||||
}
|
||||
|
||||
bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage) {
|
||||
var control = (ChromiumWebBrowser) browserControl;
|
||||
|
||||
control.InvokeSafe(() => {
|
||||
FormMessage form;
|
||||
TextBox input = null;
|
||||
|
||||
if (dialogType == CefJsDialogType.Alert) {
|
||||
form = CreateMessageForm("Browser Message", messageText);
|
||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||
}
|
||||
else if (dialogType == CefJsDialogType.Confirm) {
|
||||
form = CreateMessageForm("Browser Confirmation", messageText);
|
||||
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel);
|
||||
form.AddButton(FormMessage.Yes, ControlType.Focused);
|
||||
}
|
||||
else if (dialogType == CefJsDialogType.Prompt) {
|
||||
form = CreateMessageForm("Browser Prompt", messageText);
|
||||
form.AddButton(FormMessage.Cancel, DialogResult.Cancel, ControlType.Cancel);
|
||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||
|
||||
float dpiScale = form.GetDPIScale();
|
||||
int inputPad = form.HasIcon ? 43 : 0;
|
||||
|
||||
input = new TextBox {
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
Font = SystemFonts.MessageBoxFont,
|
||||
Location = new Point(BrowserUtils.Scale(22 + inputPad, dpiScale), form.ActionPanelY - BrowserUtils.Scale(46, dpiScale)),
|
||||
Size = new Size(form.ClientSize.Width - BrowserUtils.Scale(44 + inputPad, dpiScale), BrowserUtils.Scale(23, dpiScale))
|
||||
};
|
||||
|
||||
form.Controls.Add(input);
|
||||
form.ActiveControl = input;
|
||||
form.Height += input.Size.Height + input.Margin.Vertical;
|
||||
}
|
||||
else {
|
||||
callback.Continue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = form.ShowDialog() == DialogResult.OK;
|
||||
|
||||
if (input == null) {
|
||||
callback.Continue(success);
|
||||
}
|
||||
else {
|
||||
callback.Continue(success, input.Text);
|
||||
input.Dispose();
|
||||
}
|
||||
|
||||
callback.Dispose();
|
||||
form.Dispose();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IJsDialogHandler.OnBeforeUnloadDialog(IWebBrowser browserControl, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback) {
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IJsDialogHandler.OnResetDialogState(IWebBrowser browserControl, IBrowser browser) {}
|
||||
void IJsDialogHandler.OnDialogClosed(IWebBrowser browserControl, IBrowser browser) {}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using TweetLib.Core;
|
||||
using TweetLib.Utils.Static;
|
||||
|
||||
namespace TweetDuck.Browser.Base {
|
||||
sealed class FileDialogHandler : IDialogHandler {
|
||||
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback) {
|
||||
if (mode == CefFileDialogMode.Open || mode == CefFileDialogMode.OpenMultiple) {
|
||||
string allFilters = string.Join(";", acceptFilters.SelectMany(ParseFileType).Where(filter => !string.IsNullOrEmpty(filter)).Select(filter => "*" + filter));
|
||||
|
||||
using OpenFileDialog dialog = new OpenFileDialog {
|
||||
AutoUpgradeEnabled = true,
|
||||
DereferenceLinks = true,
|
||||
Multiselect = mode == CefFileDialogMode.OpenMultiple,
|
||||
Title = "Open Files",
|
||||
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||
string ext = Path.GetExtension(dialog.FileName)?.ToLower();
|
||||
callback.Continue(acceptFilters.FindIndex(filter => ParseFileType(filter).Contains(ext)), dialog.FileNames.ToList());
|
||||
}
|
||||
else {
|
||||
callback.Cancel();
|
||||
}
|
||||
|
||||
callback.Dispose();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> ParseFileType(string type) {
|
||||
if (string.IsNullOrEmpty(type)) {
|
||||
return StringUtils.EmptyArray;
|
||||
}
|
||||
|
||||
if (type[0] == '.') {
|
||||
return new string[] { type };
|
||||
}
|
||||
|
||||
string[] extensions = type switch {
|
||||
"image/jpeg" => new string[] { ".jpg", ".jpeg" },
|
||||
"image/png" => new string[] { ".png" },
|
||||
"image/gif" => new string[] { ".gif" },
|
||||
"image/webp" => new string[] { ".webp" },
|
||||
"video/mp4" => new string[] { ".mp4" },
|
||||
"video/quicktime" => new string[] { ".mov", ".qt" },
|
||||
_ => StringUtils.EmptyArray
|
||||
};
|
||||
|
||||
if (extensions.Length == 0) {
|
||||
App.Logger.Warn("Unknown file type: " + type);
|
||||
Debugger.Break();
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
}
|
||||
}
|
74
windows/TweetDuck/Browser/Base/JsDialogOpener.cs
Normal file
74
windows/TweetDuck/Browser/Base/JsDialogOpener.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using TweetDuck.Controls;
|
||||
using TweetDuck.Dialogs;
|
||||
using TweetDuck.Utils;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
|
||||
namespace TweetDuck.Browser.Base {
|
||||
sealed class JsDialogOpener : IJsDialogOpener {
|
||||
private static FormMessage CreateMessageForm(MessageDialogType type, string title, string text) {
|
||||
return new FormMessage(title, text, type switch {
|
||||
MessageDialogType.Error => MessageBoxIcon.Error,
|
||||
MessageDialogType.Warning => MessageBoxIcon.Warning,
|
||||
MessageDialogType.Information => MessageBoxIcon.Information,
|
||||
MessageDialogType.Question => MessageBoxIcon.Question,
|
||||
_ => MessageBoxIcon.None
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Control control;
|
||||
|
||||
public JsDialogOpener(Control control) {
|
||||
this.control = control;
|
||||
}
|
||||
|
||||
public void Alert(MessageDialogType type, string title, string message, Action<bool> callback) {
|
||||
control.InvokeSafe(() => {
|
||||
using FormMessage form = CreateMessageForm(type, title, message);
|
||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||
|
||||
bool success = form.ShowDialog() == DialogResult.OK;
|
||||
callback(success);
|
||||
});
|
||||
}
|
||||
|
||||
public void Confirm(MessageDialogType type, string title, string message, Action<bool> callback) {
|
||||
control.InvokeSafe(() => {
|
||||
using FormMessage form = CreateMessageForm(type, title, message);
|
||||
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel);
|
||||
form.AddButton(FormMessage.Yes, ControlType.Focused);
|
||||
|
||||
bool success = form.ShowDialog() == DialogResult.OK;
|
||||
callback(success);
|
||||
});
|
||||
}
|
||||
|
||||
public void Prompt(MessageDialogType type, string title, string message, Action<bool, string> callback) {
|
||||
control.InvokeSafe(() => {
|
||||
using FormMessage form = CreateMessageForm(type, title, message);
|
||||
form.AddButton(FormMessage.Cancel, DialogResult.Cancel, ControlType.Cancel);
|
||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||
|
||||
float dpiScale = form.GetDPIScale();
|
||||
int inputPad = form.HasIcon ? 43 : 0;
|
||||
|
||||
using var input = new TextBox {
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
Font = SystemFonts.MessageBoxFont,
|
||||
Location = new Point(BrowserUtils.Scale(22 + inputPad, dpiScale), form.ActionPanelY - BrowserUtils.Scale(46, dpiScale)),
|
||||
Size = new Size(form.ClientSize.Width - BrowserUtils.Scale(44 + inputPad, dpiScale), BrowserUtils.Scale(23, dpiScale))
|
||||
};
|
||||
|
||||
form.Controls.Add(input);
|
||||
form.ActiveControl = input;
|
||||
form.Height += input.Size.Height + input.Margin.Vertical;
|
||||
|
||||
bool success = form.ShowDialog() == DialogResult.OK;
|
||||
callback(success, input.Text);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -40,7 +40,6 @@ public bool IsTweetDeckWebsite {
|
||||
|
||||
public TweetDeckBrowser(FormBrowser owner, PluginManager pluginManager, ITweetDeckInterface tweetDeckInterface, UpdateChecker updateChecker) {
|
||||
this.browser = new ChromiumWebBrowser(TwitterUrls.TweetDeck) {
|
||||
DialogHandler = new FileDialogHandler(),
|
||||
KeyboardHandler = new CustomKeyboardHandler(owner)
|
||||
};
|
||||
|
||||
|
@ -105,8 +105,7 @@
|
||||
<Compile Include="Browser\Base\ContextMenuBrowser.cs" />
|
||||
<Compile Include="Browser\Base\ContextMenuNotification.cs" />
|
||||
<Compile Include="Browser\Base\CustomKeyboardHandler.cs" />
|
||||
<Compile Include="Browser\Base\FileDialogHandler.cs" />
|
||||
<Compile Include="Browser\Base\CustomJsDialogHandler.cs" />
|
||||
<Compile Include="Browser\Base\JsDialogOpener.cs" />
|
||||
<Compile Include="Browser\Base\PopupHandler.cs" />
|
||||
<Compile Include="Browser\Notification\FormNotificationExample.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
@ -0,0 +1,23 @@
|
||||
using System.Linq;
|
||||
using CefSharp;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
|
||||
namespace TweetImpl.CefSharp.Adapters {
|
||||
sealed class CefFileDialogCallbackAdapter : IFileDialogCallbackAdapter<IFileDialogCallback> {
|
||||
public static CefFileDialogCallbackAdapter Instance { get; } = new CefFileDialogCallbackAdapter();
|
||||
|
||||
private CefFileDialogCallbackAdapter() {}
|
||||
|
||||
public void Continue(IFileDialogCallback callback, int selectedAcceptFilter, string[] filePaths) {
|
||||
callback.Continue(selectedAcceptFilter, filePaths.ToList());
|
||||
}
|
||||
|
||||
public void Cancel(IFileDialogCallback callback) {
|
||||
callback.Cancel();
|
||||
}
|
||||
|
||||
public void Dispose(IFileDialogCallback callback) {
|
||||
callback.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using CefSharp;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
|
||||
namespace TweetImpl.CefSharp.Adapters {
|
||||
sealed class CefJsDialogCallbackAdapter : IJsDialogCallbackAdapter<IJsDialogCallback> {
|
||||
public static CefJsDialogCallbackAdapter Instance { get; } = new CefJsDialogCallbackAdapter();
|
||||
|
||||
private CefJsDialogCallbackAdapter() {}
|
||||
|
||||
public void Continue(IJsDialogCallback callback, bool success, string userInput = null) {
|
||||
if (userInput == null) {
|
||||
callback.Continue(success);
|
||||
}
|
||||
else {
|
||||
callback.Continue(success, userInput);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose(IJsDialogCallback callback) {
|
||||
callback.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -14,18 +14,20 @@ public abstract class BrowserComponentBase : BrowserComponent<IFrame, IRequest>
|
||||
|
||||
public ResourceHandlerRegistry<IResourceHandler> ResourceHandlerRegistry { get; } = new ResourceHandlerRegistry<IResourceHandler>(CefResourceHandlerFactory.Instance);
|
||||
|
||||
protected readonly ChromiumWebBrowser browser;
|
||||
private readonly ChromiumWebBrowser browser;
|
||||
private readonly CreateContextMenu createContextMenu;
|
||||
private readonly IJsDialogOpener jsDialogOpener;
|
||||
private readonly IPopupHandler popupHandler;
|
||||
private readonly bool autoReload;
|
||||
|
||||
protected BrowserComponentBase(ChromiumWebBrowser browser, CreateContextMenu createContextMenu, IPopupHandler popupHandler, bool autoReload) : base(new CefBrowserAdapter(browser), CefAdapter.Instance, CefFrameAdapter.Instance, CefRequestAdapter.Instance) {
|
||||
protected BrowserComponentBase(ChromiumWebBrowser browser, CreateContextMenu createContextMenu, IJsDialogOpener jsDialogOpener, IPopupHandler popupHandler, bool autoReload) : base(new CefBrowserAdapter(browser), CefAdapter.Instance, CefFrameAdapter.Instance, CefRequestAdapter.Instance) {
|
||||
this.browser = browser;
|
||||
this.browser.LoadingStateChanged += OnLoadingStateChanged;
|
||||
this.browser.LoadError += OnLoadError;
|
||||
this.browser.FrameLoadStart += OnFrameLoadStart;
|
||||
this.browser.FrameLoadEnd += OnFrameLoadEnd;
|
||||
this.createContextMenu = createContextMenu;
|
||||
this.jsDialogOpener = jsDialogOpener;
|
||||
this.popupHandler = popupHandler;
|
||||
this.autoReload = autoReload;
|
||||
}
|
||||
@ -34,8 +36,10 @@ public override void Setup(BrowserSetup setup) {
|
||||
var lifeSpanHandler = new CefLifeSpanHandler(popupHandler);
|
||||
var requestHandler = new CefRequestHandler(lifeSpanHandler, autoReload);
|
||||
|
||||
browser.DialogHandler = new CefFileDialogHandler();
|
||||
browser.DragHandler = new CefDragHandler(requestHandler, this);
|
||||
browser.LifeSpanHandler = lifeSpanHandler;
|
||||
browser.JsDialogHandler = new CefJsDialogHandler(jsDialogOpener);
|
||||
browser.MenuHandler = createContextMenu(setup.ContextMenuHandler);
|
||||
browser.RequestHandler = requestHandler;
|
||||
browser.ResourceRequestHandlerFactory = new CefResourceRequestHandlerFactory(setup.ResourceRequestHandler, ResourceHandlerRegistry);
|
||||
|
32
windows/TweetImpl.CefSharp/Dialogs/FileDialogOpener.cs
Normal file
32
windows/TweetImpl.CefSharp/Dialogs/FileDialogOpener.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
|
||||
namespace TweetImpl.CefSharp.Dialogs {
|
||||
sealed class FileDialogOpener : IFileDialogOpener {
|
||||
public static FileDialogOpener Instance { get; } = new FileDialogOpener();
|
||||
|
||||
private FileDialogOpener() {}
|
||||
|
||||
public void OpenFile(string title, bool multiple, List<string> supportedExtensions, Action<string[]> onAccepted, Action onCancelled) {
|
||||
string supportedFormatsFilter = string.Join(";", supportedExtensions.Select(filter => "*" + filter));
|
||||
|
||||
using OpenFileDialog dialog = new OpenFileDialog {
|
||||
AutoUpgradeEnabled = true,
|
||||
DereferenceLinks = true,
|
||||
Multiselect = multiple,
|
||||
Title = title,
|
||||
Filter = $"All Supported Formats ({supportedFormatsFilter})|{supportedFormatsFilter}|All Files (*.*)|*.*"
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||
onAccepted(dialog.FileNames);
|
||||
}
|
||||
else {
|
||||
onCancelled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
windows/TweetImpl.CefSharp/Handlers/CefFileDialogHandler.cs
Normal file
29
windows/TweetImpl.CefSharp/Handlers/CefFileDialogHandler.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using TweetImpl.CefSharp.Adapters;
|
||||
using TweetImpl.CefSharp.Dialogs;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
using TweetLib.Browser.CEF.Logic;
|
||||
using static TweetLib.Browser.CEF.Dialogs.FileDialogType;
|
||||
|
||||
namespace TweetImpl.CefSharp.Handlers {
|
||||
sealed class CefFileDialogHandler : IDialogHandler {
|
||||
private readonly DialogHandlerLogic<IFileDialogCallback> logic;
|
||||
|
||||
public CefFileDialogHandler() {
|
||||
this.logic = new DialogHandlerLogic<IFileDialogCallback>(FileDialogOpener.Instance, CefFileDialogCallbackAdapter.Instance);
|
||||
}
|
||||
|
||||
public bool OnFileDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback) {
|
||||
return logic.OnFileDialog(ConvertDialogType(mode), acceptFilters, callback);
|
||||
}
|
||||
|
||||
private static FileDialogType ConvertDialogType(CefFileDialogMode mode) {
|
||||
return mode switch {
|
||||
CefFileDialogMode.Open => Open,
|
||||
CefFileDialogMode.OpenMultiple => OpenMultiple,
|
||||
_ => Other
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
37
windows/TweetImpl.CefSharp/Handlers/CefJsDialogHandler.cs
Normal file
37
windows/TweetImpl.CefSharp/Handlers/CefJsDialogHandler.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CefSharp;
|
||||
using TweetImpl.CefSharp.Adapters;
|
||||
using TweetLib.Browser.CEF.Dialogs;
|
||||
using TweetLib.Browser.CEF.Interfaces;
|
||||
using TweetLib.Browser.CEF.Logic;
|
||||
|
||||
namespace TweetImpl.CefSharp.Handlers {
|
||||
sealed class CefJsDialogHandler : IJsDialogHandler {
|
||||
private readonly JsDialogHandlerLogic<IJsDialogCallback> logic;
|
||||
|
||||
public CefJsDialogHandler(IJsDialogOpener jsDialogOpener) {
|
||||
this.logic = new JsDialogHandlerLogic<IJsDialogCallback>(jsDialogOpener, CefJsDialogCallbackAdapter.Instance);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "RedundantAssignment")]
|
||||
public bool OnJSDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage) {
|
||||
return logic.OnJSDialog(ConvertDialogType(dialogType), messageText, callback, out suppressMessage);
|
||||
}
|
||||
|
||||
public bool OnBeforeUnloadDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback) {
|
||||
return logic.OnBeforeUnloadDialog(callback);
|
||||
}
|
||||
|
||||
public void OnResetDialogState(IWebBrowser chromiumWebBrowser, IBrowser browser) {}
|
||||
public void OnDialogClosed(IWebBrowser chromiumWebBrowser, IBrowser browser) {}
|
||||
|
||||
private static JsDialogType ConvertDialogType(CefJsDialogType type) {
|
||||
return type switch {
|
||||
CefJsDialogType.Alert => JsDialogType.Alert,
|
||||
CefJsDialogType.Confirm => JsDialogType.Confirm,
|
||||
CefJsDialogType.Prompt => JsDialogType.Prompt,
|
||||
_ => JsDialogType.Unknown
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -69,15 +69,20 @@
|
||||
<Compile Include="Adapters\CefBrowserAdapter.cs" />
|
||||
<Compile Include="Adapters\CefDragDataAdapter.cs" />
|
||||
<Compile Include="Adapters\CefErrorCodeAdapter.cs" />
|
||||
<Compile Include="Adapters\CefFileDialogCallbackAdapter.cs" />
|
||||
<Compile Include="Adapters\CefFrameAdapter.cs" />
|
||||
<Compile Include="Adapters\CefJsDialogCallbackAdapter.cs" />
|
||||
<Compile Include="Adapters\CefMenuModelAdapter.cs" />
|
||||
<Compile Include="Adapters\CefRequestAdapter.cs" />
|
||||
<Compile Include="Adapters\CefResponseAdapter.cs" />
|
||||
<Compile Include="Component\BrowserComponentBase.cs" />
|
||||
<Compile Include="Dialogs\FileDialogOpener.cs" />
|
||||
<Compile Include="Handlers\CefByteArrayResourceHandler.cs" />
|
||||
<Compile Include="Handlers\CefContextMenuHandler.cs" />
|
||||
<Compile Include="Handlers\CefDownloadRequestClient.cs" />
|
||||
<Compile Include="Handlers\CefDragHandler.cs" />
|
||||
<Compile Include="Handlers\CefFileDialogHandler.cs" />
|
||||
<Compile Include="Handlers\CefJsDialogHandler.cs" />
|
||||
<Compile Include="Handlers\CefLifeSpanHandler.cs" />
|
||||
<Compile Include="Handlers\CefRequestHandler.cs" />
|
||||
<Compile Include="Handlers\CefResourceHandlerFactory.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user