1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-08-13 19:16:58 +02:00
Files
.github
Application
Browser
Adapters
Bridge
Data
Handling
Notification
Example
Screenshot
FormNotificationBase.Designer.cs
FormNotificationBase.cs
FormNotificationMain.Designer.cs
FormNotificationMain.cs
FormNotificationTweet.Designer.cs
FormNotificationTweet.cs
SoundNotification.cs
FormBrowser.Designer.cs
FormBrowser.cs
FormBrowser.resx
TrayIcon.Designer.cs
TrayIcon.cs
TweetDeckBrowser.cs
Configuration
Controls
Dialogs
Management
Plugins
Properties
Resources
Updates
Utils
bld
lib
subprocess
video
.gitattributes
.gitignore
LICENSE.md
Program.cs
README.md
Reporter.cs
TweetDuck.csproj
TweetDuck.sln
TweetDuck.sln.DotSettings
Version.cs
packages.config
TweetDuck/Browser/Notification/FormNotificationMain.cs

300 lines
11 KiB
C#

using System;
using System.Drawing;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Browser.Adapters;
using TweetDuck.Browser.Bridge;
using TweetDuck.Browser.Handling;
using TweetDuck.Controls;
using TweetDuck.Plugins;
using TweetDuck.Utils;
using TweetLib.Core.Data;
using TweetLib.Core.Features.Notifications;
using TweetLib.Core.Features.Plugins;
using TweetLib.Core.Features.Plugins.Enums;
using TweetLib.Core.Features.Twitter;
namespace TweetDuck.Browser.Notification{
abstract partial class FormNotificationMain : FormNotificationBase{
private readonly PluginManager plugins;
private readonly int timerBarHeight;
protected int timeLeft, totalTime;
protected bool pausedDuringNotification;
private readonly NativeMethods.HookProc mouseHookDelegate;
private IntPtr mouseHook;
private bool blockXButtonUp;
private int currentOpacity;
private bool? prevDisplayTimer;
private int? prevFontSize;
public virtual bool RequiresResize{
get{
return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Config.DisplayNotificationTimer || prevFontSize != FontSizeLevel;
}
set{
if (value){
prevDisplayTimer = null;
prevFontSize = null;
}
else{
prevDisplayTimer = Config.DisplayNotificationTimer;
prevFontSize = FontSizeLevel;
}
}
}
private int BaseClientWidth{
get => Config.NotificationSize switch{
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Width,
_ => BrowserUtils.Scale(284, SizeScale * (1.0 + 0.05 * FontSizeLevel))
};
}
private int BaseClientHeight{
get => Config.NotificationSize switch{
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Height,
_ => BrowserUtils.Scale(122, SizeScale * (1.0 + 0.08 * FontSizeLevel))
};
}
protected virtual string BodyClasses => IsCursorOverBrowser ? "td-notification td-hover" : "td-notification";
public Size BrowserSize => Config.DisplayNotificationTimer ? new Size(ClientSize.Width, ClientSize.Height - timerBarHeight) : ClientSize;
protected FormNotificationMain(FormBrowser owner, PluginManager pluginManager, bool enableContextMenu) : base(owner, enableContextMenu){
InitializeComponent();
this.plugins = pluginManager;
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
browser.KeyboardHandler = new KeyboardHandlerNotification(this);
browser.RegisterJsBridge("$TD", new TweetDeckBridge.Notification(owner, this));
browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd;
plugins.Register(PluginEnvironment.Notification, new PluginDispatcher(browser, url => TwitterUrls.IsTweetDeck(url) && url != BlankURL));
mouseHookDelegate = MouseHookProc;
Disposed += (sender, args) => StopMouseHook(true);
}
// helpers
private void SetOpacity(int opacity){
if (currentOpacity != opacity){
currentOpacity = opacity;
Opacity = opacity / 100.0;
}
}
// mouse wheel hook
private void StartMouseHook(){
if (mouseHook == IntPtr.Zero){
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WM_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
}
}
private void StopMouseHook(bool force){
if (mouseHook != IntPtr.Zero && (force || !blockXButtonUp)){
NativeMethods.UnhookWindowsHookEx(mouseHook);
mouseHook = IntPtr.Zero;
blockXButtonUp = false;
}
}
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
if (nCode == 0){
int eventType = wParam.ToInt32();
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
int delta = BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Config.NotificationScrollSpeed * 0.01);
if (Config.EnableSmoothScrolling){
browser.ExecuteScriptAsync("window.TDGF_scrollSmoothly", (int)Math.Round(-delta / 0.6));
}
else{
browser.SendMouseWheelEvent(0, 0, 0, delta, CefEventFlags.None);
}
return NativeMethods.HOOK_HANDLED;
}
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){
int extraButton = NativeMethods.GetMouseHookData(lParam);
if (extraButton == 2){ // forward button
this.InvokeAsyncSafe(FinishCurrentNotification);
}
else if (extraButton == 1){ // back button
this.InvokeAsyncSafe(Close);
}
blockXButtonUp = true;
this.InvokeAsyncSafe(AnalyticsFile.NotificationExtraMouseButtons.Trigger);
return NativeMethods.HOOK_HANDLED;
}
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){
blockXButtonUp = false;
if (!Visible){
StopMouseHook(false);
}
return NativeMethods.HOOK_HANDLED;
}
}
return NativeMethods.CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
// event handlers
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
if (e.CloseReason == CloseReason.UserClosing){
HideNotification();
e.Cancel = true;
}
}
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
if (!e.IsLoading && browser.Address != BlankURL){
this.InvokeSafe(() => {
Visible = true; // ensures repaint before moving the window to a visible location
timerDisplayDelay.Start();
});
}
}
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
IFrame frame = e.Frame;
if (frame.IsMain && browser.Address != BlankURL){
frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
CefScriptExecutor.RunFile(frame, "notification.js");
}
}
private void timerDisplayDelay_Tick(object sender, EventArgs e){
OnNotificationReady();
timerDisplayDelay.Stop();
}
private void timerHideProgress_Tick(object sender, EventArgs e){
bool isCursorInside = Bounds.Contains(Cursor.Position);
if (isCursorInside){
StartMouseHook();
SetOpacity(100);
}
else{
StopMouseHook(false);
SetOpacity(Config.NotificationWindowOpacity);
}
if (isCursorInside || FreezeTimer || ContextMenuOpen){
return;
}
timeLeft -= timerProgress.Interval;
int value = BrowserUtils.Scale(progressBarTimer.Maximum + 25, (totalTime - timeLeft) / (double)totalTime);
progressBarTimer.SetValueInstant(Config.NotificationTimerCountDown ? progressBarTimer.Maximum - value : value);
if (timeLeft <= 0){
FinishCurrentNotification();
}
}
// notification methods
public virtual void ShowNotification(DesktopNotification notification){
LoadTweet(notification);
}
public override void HideNotification(){
base.HideNotification();
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
timerProgress.Stop();
totalTime = 0;
StopMouseHook(false);
}
public override void FinishCurrentNotification(){
timerProgress.Stop();
}
public override void PauseNotification(){
if (!IsPaused){
pausedDuringNotification = IsNotificationVisible;
timerProgress.Stop();
StopMouseHook(true);
}
base.PauseNotification();
}
public override void ResumeNotification(){
bool wasPaused = IsPaused;
base.ResumeNotification();
if (wasPaused && !IsPaused && pausedDuringNotification){
OnNotificationReady();
}
}
protected override string GetTweetHTML(DesktopNotification tweet){
string html = tweet.GenerateHtml(BodyClasses, HeadLayout, Config.CustomNotificationCSS);
foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.InjectInto(html);
}
return html;
}
protected override void LoadTweet(DesktopNotification tweet){
timerProgress.Stop();
totalTime = timeLeft = tweet.GetDisplayDuration(Config.NotificationDurationValue);
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
base.LoadTweet(tweet);
}
protected override void SetNotificationSize(int width, int height){
if (Config.DisplayNotificationTimer){
ClientSize = new Size(width, height + timerBarHeight);
progressBarTimer.Visible = true;
}
else{
ClientSize = new Size(width, height);
progressBarTimer.Visible = false;
}
browser.ClientSize = new Size(width, height);
}
protected void PrepareAndDisplayWindow(){
if (RequiresResize){
RequiresResize = false;
SetNotificationSize(BaseClientWidth, BaseClientHeight);
}
SetOpacity(IsCursorOverBrowser ? 100 : Config.NotificationWindowOpacity);
MoveToVisibleLocation();
}
protected virtual void OnNotificationReady(){
PrepareAndDisplayWindow();
timerProgress.Start();
}
}
}