mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-12 14:34:08 +02:00
Initial refactoring of ScriptLoader & making it accessible in TweetLib.Core
This commit is contained in:
parent
a34a02e14d
commit
d505b3305b
@ -1,15 +1,12 @@
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using CefSharp;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Browser;
|
||||
|
||||
namespace TweetDuck.Core.Adapters{
|
||||
sealed class CefScriptExecutor : IScriptExecutor{
|
||||
private readonly Control sync;
|
||||
private readonly IWebBrowser browser;
|
||||
|
||||
public CefScriptExecutor(Control sync, IWebBrowser browser){
|
||||
this.sync = sync;
|
||||
public CefScriptExecutor(IWebBrowser browser){
|
||||
this.browser = browser;
|
||||
}
|
||||
|
||||
@ -19,12 +16,26 @@ public void RunFunction(string name, params object[] args){
|
||||
|
||||
public void RunScript(string identifier, string script){
|
||||
using IFrame frame = browser.GetMainFrame();
|
||||
ScriptLoader.ExecuteScript(frame, script, identifier);
|
||||
RunScript(frame, script, identifier);
|
||||
}
|
||||
|
||||
public bool RunFile(string file){
|
||||
using IFrame frame = browser.GetMainFrame();
|
||||
return ScriptLoader.ExecuteFile(frame, file, sync);
|
||||
return RunFile(frame, file);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
public static void RunScript(IFrame frame, string script, string identifier){
|
||||
if (script != null){
|
||||
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RunFile(IFrame frame, string file){
|
||||
string script = Program.Resources.Load(file);
|
||||
RunScript(frame, script, "root:" + Path.GetFileNameWithoutExtension(file));
|
||||
return script != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,12 @@
|
||||
using TweetDuck.Core.Utils;
|
||||
using System.Linq;
|
||||
using TweetDuck.Configuration;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Core.Bridge;
|
||||
using TweetDuck.Core.Management;
|
||||
using TweetDuck.Core.Notification;
|
||||
using TweetDuck.Core.Other;
|
||||
using TweetDuck.Core.Other.Analytics;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Features.Twitter;
|
||||
using TweetLib.Core.Utils;
|
||||
|
||||
@ -194,7 +194,7 @@ public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser,
|
||||
}
|
||||
|
||||
protected static void DeselectAll(IFrame frame){
|
||||
ScriptLoader.ExecuteScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
|
||||
CefScriptExecutor.RunScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
|
||||
}
|
||||
|
||||
protected static void OpenBrowser(Control control, string url){
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using TweetDuck.Core.Controls;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Features.Plugins;
|
||||
|
||||
namespace TweetDuck.Core.Notification.Example{
|
||||
@ -32,7 +31,7 @@ protected override FormBorderStyle NotificationBorderStyle{
|
||||
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
|
||||
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
||||
|
||||
string exampleTweetHTML = ScriptLoader.LoadResourceSilent("pages/example.html")?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
|
||||
string exampleTweetHTML = Program.Resources.LoadSilent("pages/example.html")?.Replace("{avatar}", AppLogo.Url) ?? string.Empty;
|
||||
|
||||
#if DEBUG
|
||||
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
|
||||
|
@ -2,12 +2,12 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Core.Bridge;
|
||||
using TweetDuck.Core.Controls;
|
||||
using TweetDuck.Core.Handling;
|
||||
using TweetDuck.Core.Utils;
|
||||
using TweetDuck.Plugins;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Data;
|
||||
using TweetLib.Core.Features.Plugins;
|
||||
using TweetLib.Core.Features.Plugins.Enums;
|
||||
@ -74,7 +74,7 @@ protected FormNotificationMain(FormBrowser owner, PluginManager pluginManager, b
|
||||
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
||||
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
||||
|
||||
plugins.Register(PluginEnvironment.Notification, new PluginDispatcher(this, browser));
|
||||
plugins.Register(PluginEnvironment.Notification, new PluginDispatcher(browser));
|
||||
|
||||
mouseHookDelegate = MouseHookProc;
|
||||
Disposed += (sender, args) => StopMouseHook(true);
|
||||
@ -155,7 +155,7 @@ private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||
|
||||
if (frame.IsMain && browser.Address != "about:blank"){
|
||||
frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
|
||||
ScriptLoader.ExecuteFile(frame, "notification.js", this);
|
||||
CefScriptExecutor.RunFile(frame, "notification.js");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,10 @@
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Core.Controls;
|
||||
using TweetDuck.Core.Other;
|
||||
using TweetDuck.Core.Utils;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Data;
|
||||
using TweetLib.Core.Features.Plugins;
|
||||
|
||||
@ -29,16 +29,15 @@ public FormNotificationScreenshotable(Action callback, FormBrowser owner, Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
string script = ScriptLoader.LoadResourceSilent("screenshot.js");
|
||||
|
||||
string script = Program.Resources.LoadSilent("screenshot.js");
|
||||
|
||||
if (script == null){
|
||||
this.InvokeAsyncSafe(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
using(IFrame frame = args.Browser.MainFrame){
|
||||
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
|
||||
}
|
||||
|
||||
using IFrame frame = args.Browser.MainFrame;
|
||||
CefScriptExecutor.RunScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
|
||||
};
|
||||
|
||||
SetNotificationSize(realWidth, 1024);
|
||||
|
@ -7,8 +7,8 @@
|
||||
using TweetDuck.Core.Handling.General;
|
||||
using TweetDuck.Core.Utils;
|
||||
using System.Text.RegularExpressions;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Data;
|
||||
using TweetDuck.Resources;
|
||||
|
||||
namespace TweetDuck.Core.Other{
|
||||
sealed partial class FormGuide : Form, FormManager.IAppDialog{
|
||||
@ -116,7 +116,7 @@ private void browser_LoadingStateChanged(object sender, LoadingStateChangedEvent
|
||||
}
|
||||
|
||||
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||
ScriptLoader.ExecuteScript(e.Frame, "Array.prototype.forEach.call(document.getElementsByTagName('A'), ele => ele.addEventListener('click', e => { e.preventDefault(); window.open(ele.getAttribute('href')); }))", "gen:links");
|
||||
CefScriptExecutor.RunScript(e.Frame, "Array.prototype.forEach.call(document.getElementsByTagName('A'), ele => ele.addEventListener('click', e => { e.preventDefault(); window.open(ele.getAttribute('href')); }))", "gen:links");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using TweetDuck.Configuration;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Core.Bridge;
|
||||
using TweetDuck.Core.Controls;
|
||||
using TweetDuck.Core.Handling;
|
||||
@ -12,7 +13,6 @@
|
||||
using TweetDuck.Core.Notification;
|
||||
using TweetDuck.Core.Utils;
|
||||
using TweetDuck.Plugins;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core.Features.Plugins;
|
||||
using TweetLib.Core.Features.Plugins.Enums;
|
||||
|
||||
@ -48,7 +48,7 @@ public bool IsTweetDeckWebsite{
|
||||
private string prevSoundNotificationPath = null;
|
||||
|
||||
public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridge tdBridge, UpdateBridge updateBridge){
|
||||
resourceHandlerFactory.RegisterHandler(TweetNotification.AppLogo);
|
||||
resourceHandlerFactory.RegisterHandler(FormNotificationBase.AppLogo);
|
||||
resourceHandlerFactory.RegisterHandler(TwitterUtils.LoadingSpinner);
|
||||
|
||||
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
||||
@ -78,7 +78,7 @@ public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridg
|
||||
this.browser.SetupZoomEvents();
|
||||
|
||||
owner.Controls.Add(browser);
|
||||
plugins.Register(PluginEnvironment.Browser, new PluginDispatcher(owner, browser));
|
||||
plugins.Register(PluginEnvironment.Browser, new PluginDispatcher(browser));
|
||||
|
||||
Config.MuteToggled += Config_MuteToggled;
|
||||
Config.SoundNotificationChanged += Config_SoundNotificationInfoChanged;
|
||||
@ -123,10 +123,10 @@ private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){
|
||||
|
||||
if (frame.IsMain){
|
||||
if (TwitterUtils.IsTwitterWebsite(frame)){
|
||||
string css = ScriptLoader.LoadResource("styles/twitter.css", browser);
|
||||
string css = Program.Resources.Load("styles/twitter.css");
|
||||
resourceHandlerFactory.RegisterHandler(TwitterStyleUrl, ResourceHandler.FromString(css, mimeType: "text/css"));
|
||||
|
||||
ScriptLoader.ExecuteFile(frame, "twitter.js", browser);
|
||||
CefScriptExecutor.RunFile(frame, "twitter.js");
|
||||
}
|
||||
|
||||
if (!TwitterUtils.IsTwitterLogin2FactorWebsite(frame)){
|
||||
@ -141,7 +141,7 @@ private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||
if (frame.IsMain){
|
||||
if (TwitterUtils.IsTweetDeckWebsite(frame)){
|
||||
UpdateProperties();
|
||||
ScriptLoader.ExecuteFile(frame, "code.js", browser);
|
||||
CefScriptExecutor.RunFile(frame, "code.js");
|
||||
|
||||
InjectBrowserCSS();
|
||||
ReinjectCustomCSS(Config.CustomBrowserCSS);
|
||||
@ -150,15 +150,15 @@ private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||
TweetDeckBridge.ResetStaticProperties();
|
||||
|
||||
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
|
||||
ScriptLoader.ExecuteScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
||||
CefScriptExecutor.RunScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
||||
}
|
||||
|
||||
if (Config.FirstRun){
|
||||
ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
|
||||
CefScriptExecutor.RunFile(frame, "introduction.js");
|
||||
}
|
||||
}
|
||||
|
||||
ScriptLoader.ExecuteFile(frame, "update.js", browser);
|
||||
CefScriptExecutor.RunFile(frame, "update.js");
|
||||
}
|
||||
|
||||
if (frame.Url == ErrorUrl){
|
||||
@ -172,7 +172,7 @@ private void browser_LoadError(object sender, LoadErrorEventArgs e){
|
||||
}
|
||||
|
||||
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
||||
string errorPage = ScriptLoader.LoadResourceSilent("pages/error.html");
|
||||
string errorPage = Program.Resources.LoadSilent("pages/error.html");
|
||||
|
||||
if (errorPage != null){
|
||||
resourceHandlerFactory.RegisterHandler(ErrorUrl, ResourceHandler.FromString(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode))));
|
||||
@ -226,7 +226,7 @@ public void UpdateProperties(){
|
||||
}
|
||||
|
||||
public void InjectBrowserCSS(){
|
||||
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", browser)?.TrimEnd() ?? string.Empty);
|
||||
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", Program.Resources.Load("styles/browser.css")?.TrimEnd() ?? string.Empty);
|
||||
}
|
||||
|
||||
public void ReinjectCustomCSS(string css){
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using TweetDuck.Core.Adapters;
|
||||
using TweetDuck.Core.Utils;
|
||||
@ -14,10 +13,10 @@ sealed class PluginDispatcher : IPluginDispatcher{
|
||||
private readonly IWebBrowser browser;
|
||||
private readonly IScriptExecutor executor;
|
||||
|
||||
public PluginDispatcher(Control sync, IWebBrowser browser){
|
||||
public PluginDispatcher(IWebBrowser browser){
|
||||
this.browser = browser;
|
||||
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
|
||||
this.executor = new CefScriptExecutor(sync, browser);
|
||||
this.executor = new CefScriptExecutor(browser);
|
||||
}
|
||||
|
||||
void IPluginDispatcher.AttachBridge(string name, object bridge){
|
||||
|
@ -13,6 +13,7 @@
|
||||
using TweetDuck.Core.Management;
|
||||
using TweetDuck.Core.Utils;
|
||||
using TweetDuck.Impl;
|
||||
using TweetDuck.Resources;
|
||||
using TweetLib.Core;
|
||||
using TweetLib.Core.Collections;
|
||||
using TweetLib.Core.Utils;
|
||||
@ -51,16 +52,19 @@ static class Program{
|
||||
|
||||
public static Reporter Reporter { get; }
|
||||
public static ConfigManager Config { get; }
|
||||
public static ScriptLoader Resources { get; }
|
||||
|
||||
static Program(){
|
||||
Reporter = new Reporter(ErrorLogFilePath);
|
||||
Reporter.SetupUnhandledExceptionHandler("TweetDuck Has Failed :(");
|
||||
|
||||
Config = new ConfigManager();
|
||||
Resources = new ScriptLoader();
|
||||
|
||||
Lib.Initialize(new App.Builder{
|
||||
ErrorHandler = Reporter,
|
||||
SystemHandler = new SystemHandler()
|
||||
SystemHandler = new SystemHandler(),
|
||||
ResourceHandler = Resources
|
||||
});
|
||||
}
|
||||
|
||||
@ -158,6 +162,7 @@ private static void Main(){
|
||||
Application.ApplicationExit += (sender, args) => ExitCleanup();
|
||||
|
||||
FormBrowser mainForm = new FormBrowser();
|
||||
Resources.Initialize(mainForm);
|
||||
Application.Run(mainForm);
|
||||
|
||||
if (mainForm.UpdateInstallerPath != null){
|
||||
|
@ -1,11 +1,11 @@
|
||||
using CefSharp;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using TweetDuck.Core.Controls;
|
||||
using TweetDuck.Core.Other;
|
||||
using TweetLib.Core.Application;
|
||||
|
||||
#if DEBUG
|
||||
using System.Diagnostics;
|
||||
@ -15,14 +15,35 @@
|
||||
#endif
|
||||
|
||||
namespace TweetDuck.Resources{
|
||||
static class ScriptLoader{
|
||||
sealed class ScriptLoader : IAppResourceHandler{
|
||||
private static readonly Dictionary<string, string> CachedData = new Dictionary<string, string>(16);
|
||||
|
||||
public static string LoadResourceSilent(string name){
|
||||
return LoadResource(name, null);
|
||||
public static void ClearCache(){
|
||||
CachedData.Clear();
|
||||
}
|
||||
|
||||
public static string LoadResource(string name, Control sync){
|
||||
private Control sync;
|
||||
|
||||
public void Initialize(Control sync){
|
||||
this.sync = sync;
|
||||
}
|
||||
|
||||
public string Load(string path){
|
||||
return LoadInternal(path, silent: false);
|
||||
}
|
||||
|
||||
public string LoadSilent(string path){
|
||||
return LoadInternal(path, silent: true);
|
||||
}
|
||||
|
||||
private string LoadInternal(string name, bool silent){
|
||||
if (sync == null){
|
||||
throw new InvalidOperationException("Cannot use ScriptLoader before initialization.");
|
||||
}
|
||||
else if (sync.IsDisposed){
|
||||
return null; // better than crashing I guess...?
|
||||
}
|
||||
|
||||
if (CachedData.TryGetValue(name, out string resourceData)){
|
||||
return resourceData;
|
||||
}
|
||||
@ -32,7 +53,7 @@ public static string LoadResource(string name, Control sync){
|
||||
#if DEBUG
|
||||
if (Directory.Exists(HotSwapTargetDir)){
|
||||
path = Path.Combine(HotSwapTargetDir, "scripts");
|
||||
Debug.WriteLine("Hot swap active, redirecting "+name);
|
||||
Debug.WriteLine($"Hot swap active, redirecting {name}");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -47,7 +68,7 @@ public static string LoadResource(string name, Control sync){
|
||||
// #<version>\n
|
||||
|
||||
if (contents[0] != '#'){
|
||||
ShowLoadError(sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
|
||||
ShowLoadError(silent ? null : sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
|
||||
separator = 0;
|
||||
}
|
||||
else{
|
||||
@ -55,39 +76,25 @@ public static string LoadResource(string name, Control sync){
|
||||
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
|
||||
|
||||
if (fileVersion != Program.VersionTag){
|
||||
ShowLoadError(sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
||||
ShowLoadError(silent ? null : sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
||||
}
|
||||
}
|
||||
|
||||
resource = contents.Substring(separator).TrimStart();
|
||||
}catch(Exception ex){
|
||||
ShowLoadError(sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
||||
ShowLoadError(silent ? null : sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
||||
resource = null;
|
||||
}
|
||||
|
||||
return CachedData[name] = resource;
|
||||
}
|
||||
|
||||
public static bool ExecuteFile(IFrame frame, string file, Control sync){
|
||||
string script = LoadResource(file, sync);
|
||||
ExecuteScript(frame, script, "root:"+Path.GetFileNameWithoutExtension(file));
|
||||
return script != null;
|
||||
}
|
||||
|
||||
public static void ExecuteScript(IFrame frame, string script, string identifier){
|
||||
if (script != null){
|
||||
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearCache(){
|
||||
CachedData.Clear();
|
||||
}
|
||||
|
||||
private static void ShowLoadError(Control sync, string message){
|
||||
sync?.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
|
||||
}
|
||||
|
||||
// TODO move hot swap to another implementation
|
||||
|
||||
#if DEBUG
|
||||
private static readonly string HotSwapProjectRoot = FixPathSlash(Path.GetFullPath(Path.Combine(Program.ProgramPath, "../../../")));
|
||||
private static readonly string HotSwapTargetDir = FixPathSlash(Path.Combine(HotSwapProjectRoot, "bin", "tmp"));
|
||||
@ -104,7 +111,7 @@ static ScriptLoader(){
|
||||
|
||||
public static void HotSwap(){
|
||||
if (!File.Exists(HotSwapRebuildScript)){
|
||||
Debug.WriteLine("Failed resource hot swap, missing rebuild script: "+HotSwapRebuildScript);
|
||||
Debug.WriteLine($"Failed resource hot swap, missing rebuild script: {HotSwapRebuildScript}");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -124,13 +131,13 @@ public static void HotSwap(){
|
||||
return;
|
||||
}
|
||||
else if (process.ExitCode != 0){
|
||||
Debug.WriteLine("Failed resource hot swap, script exited with code "+process.ExitCode);
|
||||
Debug.WriteLine($"Failed resource hot swap, script exited with code {process.ExitCode}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Debug.WriteLine("Finished rebuild script in "+sw.ElapsedMilliseconds+" ms");
|
||||
Debug.WriteLine($"Finished rebuild script in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
ClearCache();
|
||||
|
||||
@ -159,7 +166,7 @@ private static void ResetHotSwap(){
|
||||
}
|
||||
|
||||
private static string FixPathSlash(string path){
|
||||
return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)+'\\';
|
||||
return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + '\\';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -5,18 +5,21 @@ namespace TweetLib.Core{
|
||||
public sealed class App{
|
||||
public static IAppErrorHandler ErrorHandler { get; private set; }
|
||||
public static IAppSystemHandler SystemHandler { get; private set; }
|
||||
public static IAppResourceHandler ResourceHandler { get; private set; }
|
||||
|
||||
// Builder
|
||||
|
||||
public sealed class Builder{
|
||||
public IAppErrorHandler? ErrorHandler { get; set; }
|
||||
public IAppSystemHandler? SystemHandler { get; set; }
|
||||
public IAppResourceHandler? ResourceHandler { get; set; }
|
||||
|
||||
// Validation
|
||||
|
||||
internal void Initialize(){
|
||||
App.ErrorHandler = Validate(ErrorHandler, nameof(ErrorHandler))!;
|
||||
App.SystemHandler = Validate(SystemHandler, nameof(SystemHandler))!;
|
||||
App.ResourceHandler = Validate(ResourceHandler, nameof(ResourceHandler))!;
|
||||
}
|
||||
|
||||
private T Validate<T>(T obj, string name){
|
||||
|
5
lib/TweetLib.Core/Application/IAppResourceHandler.cs
Normal file
5
lib/TweetLib.Core/Application/IAppResourceHandler.cs
Normal file
@ -0,0 +1,5 @@
|
||||
namespace TweetLib.Core.Application{
|
||||
public interface IAppResourceHandler{
|
||||
string? Load(string path);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user