mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-28 09:15:46 +02:00
252 lines
7.7 KiB
C#
252 lines
7.7 KiB
C#
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using CefSharp.WinForms;
|
|
using TweetDuck.Browser.Adapters;
|
|
using TweetDuck.Browser.Handling;
|
|
using TweetDuck.Configuration;
|
|
using TweetDuck.Controls;
|
|
using TweetDuck.Utils;
|
|
using TweetLib.Browser.Interfaces;
|
|
using TweetLib.Core.Features.Notifications;
|
|
using TweetLib.Core.Features.Twitter;
|
|
using TweetLib.Core.Systems.Configuration;
|
|
|
|
namespace TweetDuck.Browser.Notification {
|
|
abstract partial class FormNotificationBase : Form {
|
|
protected static UserConfig Config => Program.Config.User;
|
|
|
|
protected delegate NotificationBrowser CreateBrowserImplFunc(FormNotificationBase form, IBrowserComponent browserComponent);
|
|
|
|
protected virtual Point PrimaryLocation {
|
|
get {
|
|
Screen screen;
|
|
|
|
if (Config.NotificationDisplay > 0 && Config.NotificationDisplay <= Screen.AllScreens.Length) {
|
|
screen = Screen.AllScreens[Config.NotificationDisplay - 1];
|
|
}
|
|
else {
|
|
screen = Screen.FromControl(owner);
|
|
}
|
|
|
|
int edgeDist = Config.NotificationEdgeDistance;
|
|
|
|
switch (Config.NotificationPosition) {
|
|
case DesktopNotification.Position.TopLeft:
|
|
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + edgeDist);
|
|
|
|
case DesktopNotification.Position.TopRight:
|
|
return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);
|
|
|
|
case DesktopNotification.Position.BottomLeft:
|
|
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);
|
|
|
|
case DesktopNotification.Position.BottomRight:
|
|
return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);
|
|
|
|
case DesktopNotification.Position.Custom:
|
|
if (!Config.IsCustomNotificationPositionSet) {
|
|
Config.CustomNotificationPosition = new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);
|
|
Config.Save();
|
|
}
|
|
|
|
return Config.CustomNotificationPosition;
|
|
}
|
|
|
|
return Location;
|
|
}
|
|
}
|
|
|
|
protected bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
|
|
protected virtual bool CanDragWindow => true;
|
|
|
|
public new Point Location {
|
|
get {
|
|
return base.Location;
|
|
}
|
|
|
|
set {
|
|
Visible = (base.Location = value) != ControlExtensions.InvisibleLocation;
|
|
FormBorderStyle = NotificationBorderStyle;
|
|
}
|
|
}
|
|
|
|
protected virtual FormBorderStyle NotificationBorderStyle {
|
|
get {
|
|
if (WindowsUtils.ShouldAvoidToolWindow && Visible) { // Visible = workaround for alt+tab
|
|
return FormBorderStyle.FixedSingle;
|
|
}
|
|
else {
|
|
return FormBorderStyle.FixedToolWindow;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override bool ShowWithoutActivation => true;
|
|
|
|
protected float DpiScale { get; }
|
|
protected double SizeScale => DpiScale * Config.ZoomLevel / 100.0;
|
|
|
|
private readonly FormBrowser owner;
|
|
|
|
protected readonly IBrowserComponent browserComponent;
|
|
private readonly NotificationBrowser browserImpl;
|
|
|
|
#pragma warning disable IDE0069 // Disposable fields should be disposed
|
|
protected readonly ChromiumWebBrowser browser;
|
|
#pragma warning restore IDE0069 // Disposable fields should be disposed
|
|
|
|
private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification();
|
|
|
|
private DesktopNotification currentNotification;
|
|
private int pauseCounter;
|
|
|
|
public string CurrentTweetUrl => currentNotification?.TweetUrl;
|
|
public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
|
|
|
|
protected bool IsPaused => pauseCounter > 0;
|
|
protected internal bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
|
|
|
|
public bool FreezeTimer { get; set; }
|
|
public bool ContextMenuOpen { get; set; }
|
|
|
|
protected FormNotificationBase(FormBrowser owner, CreateBrowserImplFunc createBrowserImpl) {
|
|
InitializeComponent();
|
|
|
|
this.owner = owner;
|
|
this.owner.FormClosed += owner_FormClosed;
|
|
|
|
this.browser = new ChromiumWebBrowser(NotificationBrowser.BlankURL) {
|
|
RequestHandler = new RequestHandlerBase(false)
|
|
};
|
|
|
|
this.browserComponent = new ComponentImpl(browser, this);
|
|
this.browserImpl = createBrowserImpl(this, browserComponent);
|
|
|
|
this.browser.Dock = DockStyle.None;
|
|
this.browser.ClientSize = ClientSize;
|
|
|
|
Controls.Add(browser);
|
|
|
|
Disposed += (sender, args) => {
|
|
this.owner.FormClosed -= owner_FormClosed;
|
|
this.browserImpl.Dispose();
|
|
this.browser.Dispose();
|
|
};
|
|
|
|
DpiScale = this.GetDPIScale();
|
|
|
|
// ReSharper disable once VirtualMemberCallInContructor
|
|
UpdateTitle();
|
|
}
|
|
|
|
protected sealed class ComponentImpl : CefBrowserComponent {
|
|
private readonly FormNotificationBase owner;
|
|
|
|
public ComponentImpl(ChromiumWebBrowser browser, FormNotificationBase owner) : base(browser) {
|
|
this.owner = owner;
|
|
}
|
|
|
|
protected override ContextMenuBase SetupContextMenu(IContextMenuHandler handler) {
|
|
return new ContextMenuNotification(owner, handler);
|
|
}
|
|
|
|
protected override CefResourceHandlerFactory SetupResourceHandlerFactory(IResourceRequestHandler handler) {
|
|
var registry = new CefResourceHandlerRegistry();
|
|
registry.RegisterStatic(NotificationBrowser.BlankURL, string.Empty);
|
|
registry.RegisterDynamic(TwitterUrls.TweetDeck, owner.resourceHandler);
|
|
return new CefResourceHandlerFactory(handler, registry);
|
|
}
|
|
}
|
|
|
|
protected override void Dispose(bool disposing) {
|
|
if (disposing) {
|
|
components?.Dispose();
|
|
resourceHandler.Dispose();
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
protected override void WndProc(ref Message m) {
|
|
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanDragWindow) { // WM_SYSCOMMAND, SC_MOVE
|
|
return;
|
|
}
|
|
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
// event handlers
|
|
|
|
private void owner_FormClosed(object sender, FormClosedEventArgs e) {
|
|
Close();
|
|
}
|
|
|
|
// notification methods
|
|
|
|
public virtual void HideNotification() {
|
|
browser.Load(NotificationBrowser.BlankURL);
|
|
DisplayTooltip(null);
|
|
|
|
Location = ControlExtensions.InvisibleLocation;
|
|
currentNotification = null;
|
|
}
|
|
|
|
public virtual void FinishCurrentNotification() {}
|
|
|
|
public virtual void PauseNotification() {
|
|
if (pauseCounter++ == 0 && IsNotificationVisible) {
|
|
Location = ControlExtensions.InvisibleLocation;
|
|
}
|
|
}
|
|
|
|
public virtual void ResumeNotification() {
|
|
if (pauseCounter > 0) {
|
|
--pauseCounter;
|
|
}
|
|
}
|
|
|
|
protected virtual void LoadTweet(DesktopNotification tweet) {
|
|
currentNotification = tweet;
|
|
resourceHandler.SetHTML(browserImpl.GetTweetHTML(tweet));
|
|
|
|
browser.Load(TwitterUrls.TweetDeck);
|
|
DisplayTooltip(null);
|
|
}
|
|
|
|
protected virtual void SetNotificationSize(int width, int height) {
|
|
browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale));
|
|
}
|
|
|
|
protected virtual void UpdateTitle() {
|
|
string title = currentNotification?.ColumnTitle;
|
|
Text = string.IsNullOrEmpty(title) || !Config.DisplayNotificationColumn ? Program.BrandName : $"{Program.BrandName} - {title}";
|
|
}
|
|
|
|
public void ShowTweetDetail() {
|
|
if (currentNotification != null && owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl)) {
|
|
FinishCurrentNotification();
|
|
}
|
|
}
|
|
|
|
public void MoveToVisibleLocation() {
|
|
bool needsReactivating = Location == ControlExtensions.InvisibleLocation;
|
|
Location = PrimaryLocation;
|
|
|
|
if (needsReactivating) {
|
|
NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
public void DisplayTooltip(string text) {
|
|
if (string.IsNullOrEmpty(text)) {
|
|
toolTip.Hide(this);
|
|
}
|
|
else {
|
|
Point position = PointToClient(Cursor.Position);
|
|
position.Offset(20, 5);
|
|
toolTip.Show(text, this, position);
|
|
}
|
|
}
|
|
}
|
|
}
|