mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-22 18:15:47 +02:00
Add a WIP notification system (buggy startup, missing navigation, bad UI and UX)
This commit is contained in:
parent
b9c93bfe20
commit
2834a9a443
@ -18,6 +18,7 @@ private static UserConfig Config{
|
||||
|
||||
private readonly ChromiumWebBrowser browser;
|
||||
private readonly TweetDeckBridge bridge;
|
||||
private readonly FormNotification notification;
|
||||
|
||||
public FormBrowser(){
|
||||
InitializeComponent();
|
||||
@ -29,6 +30,9 @@ public FormBrowser(){
|
||||
browser.RegisterJsObject("$TD",bridge);
|
||||
|
||||
Controls.Add(browser);
|
||||
|
||||
notification = new FormNotification(this);
|
||||
notification.Show(this);
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message m){
|
||||
@ -97,5 +101,9 @@ public void OpenSettings(){
|
||||
public void OpenAbout(){
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void OnTweetPopup(string tweetHtml, string tweetColumn){
|
||||
notification.ShowNotification(new TweetNotification(tweetHtml));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
Core/FormNotification.Designer.cs
generated
Normal file
54
Core/FormNotification.Designer.cs
generated
Normal file
@ -0,0 +1,54 @@
|
||||
namespace TweetDick.Core {
|
||||
partial class FormNotification {
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if (disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.timer = new System.Windows.Forms.Timer(this.components);
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// timer
|
||||
//
|
||||
this.timer.Tick += new System.EventHandler(this.timer_Tick);
|
||||
//
|
||||
// FormNotification
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(284, 118);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
|
||||
this.Location = new System.Drawing.Point(32000, 32000);
|
||||
this.Name = "FormNotification";
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
this.Text = "TweetDick";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormNotification_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Timer timer;
|
||||
}
|
||||
}
|
86
Core/FormNotification.cs
Normal file
86
Core/FormNotification.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using TweetDick.Core.Handling;
|
||||
|
||||
namespace TweetDick.Core{
|
||||
partial class FormNotification : Form{
|
||||
private readonly FormBrowser owner;
|
||||
private readonly ChromiumWebBrowser browser;
|
||||
|
||||
private readonly Queue<TweetNotification> tweetQueue = new Queue<TweetNotification>(4);
|
||||
|
||||
public FormNotification(FormBrowser owner){
|
||||
InitializeComponent();
|
||||
|
||||
this.owner = owner;
|
||||
|
||||
browser = new ChromiumWebBrowser(""){ MenuHandler = new MenuHandlerEmpty() };
|
||||
Controls.Add(browser);
|
||||
}
|
||||
|
||||
public void ShowNotification(TweetNotification notification){
|
||||
Screen screen = Screen.FromControl(owner);
|
||||
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-16-Width,screen.WorkingArea.Y+16);
|
||||
|
||||
tweetQueue.Enqueue(notification);
|
||||
|
||||
if (!timer.Enabled){
|
||||
LoadNextNotification();
|
||||
}
|
||||
}
|
||||
|
||||
public void HideNotification(){
|
||||
browser.Load("about:blank");
|
||||
Location = new Point(32000,32000);
|
||||
}
|
||||
|
||||
private void LoadNextNotification(){
|
||||
TweetNotification tweet = tweetQueue.Dequeue();
|
||||
|
||||
browser.Load("about:blank");
|
||||
browser.LoadHtml(tweet.GenerateHtml(),"http://tweetdeck.twitter.com/");
|
||||
|
||||
timer.Stop();
|
||||
timer.Interval = 5000;
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void timer_Tick(object sender, EventArgs e){
|
||||
if (tweetQueue.Count > 0){
|
||||
LoadNextNotification();
|
||||
}
|
||||
else{
|
||||
HideNotification();
|
||||
}
|
||||
}
|
||||
|
||||
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
|
||||
if (e.CloseReason == CloseReason.UserClosing){
|
||||
HideNotification();
|
||||
tweetQueue.Clear();
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
private class MenuHandlerEmpty : IContextMenuHandler{
|
||||
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||
model.Clear();
|
||||
}
|
||||
|
||||
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
|
||||
|
||||
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,12 +6,30 @@ public TweetDeckBridge(FormBrowser form){
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
public void LoadFontSizeClass(string fsClass){
|
||||
form.InvokeSafe(() => {
|
||||
TweetNotification.SetFontSizeClass(fsClass);
|
||||
});
|
||||
}
|
||||
|
||||
public void LoadNotificationHeadContents(string headContents){
|
||||
form.InvokeSafe(() => {
|
||||
TweetNotification.SetHeadTag(headContents);
|
||||
});
|
||||
}
|
||||
|
||||
public void OpenSettingsMenu(){
|
||||
form.InvokeSafe(() => {
|
||||
form.OpenSettings();
|
||||
});
|
||||
}
|
||||
|
||||
public void OnTweetPopup(string tweetHtml, string tweetColumn){
|
||||
form.InvokeSafe(() => {
|
||||
form.OnTweetPopup(tweetHtml,tweetColumn);
|
||||
});
|
||||
}
|
||||
|
||||
public void Log(string data){
|
||||
System.Diagnostics.Debug.WriteLine(data);
|
||||
}
|
||||
|
34
Core/Handling/TweetNotification.cs
Normal file
34
Core/Handling/TweetNotification.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System.Text;
|
||||
|
||||
namespace TweetDick.Core.Handling{
|
||||
sealed class TweetNotification{
|
||||
private static string FontSizeClass { get; set; }
|
||||
private static string HeadTag { get; set; }
|
||||
|
||||
public static void SetFontSizeClass(string newFSClass){
|
||||
FontSizeClass = newFSClass;
|
||||
}
|
||||
|
||||
public static void SetHeadTag(string headContents){
|
||||
HeadTag = headContents;
|
||||
}
|
||||
|
||||
private readonly string html;
|
||||
|
||||
public TweetNotification(string html){
|
||||
this.html = html;
|
||||
}
|
||||
|
||||
public string GenerateHtml(){
|
||||
StringBuilder build = new StringBuilder();
|
||||
build.Append("<!DOCTYPE html>");
|
||||
build.Append("<html class='os-windows ").Append(FontSizeClass).Append("'>");
|
||||
build.Append("<head>").Append(HeadTag).Append("</head>");
|
||||
build.Append("<body class='hearty'><div class='app-columns-container'><div class='column' style='width:100%'>");
|
||||
build.Append(html);
|
||||
build.Append("</div></div></body>");
|
||||
build.Append("</html>");
|
||||
return build.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,19 @@
|
||||
(function($,$TD){
|
||||
//
|
||||
// Constant: List of valid font size classes.
|
||||
//
|
||||
var fontSizeClasses = [ "txt-base-smallest", "txt-base-small", "txt-base-medium", "txt-base-large", "txt-base-largest" ];
|
||||
|
||||
//
|
||||
// Variable: Says whether TweetDick events was initialized.
|
||||
//
|
||||
var isInitialized = false;
|
||||
|
||||
//
|
||||
// Variable: Previous font size class in the <html> tag.
|
||||
//
|
||||
var prevFontSizeClass;
|
||||
|
||||
//
|
||||
// Function: Initializes TweetDick events. Called after the website app is loaded.
|
||||
//
|
||||
@ -29,9 +39,94 @@
|
||||
},0);
|
||||
});
|
||||
|
||||
// Tweet notifications
|
||||
(function(){
|
||||
var columns = $(".js-app-columns").first();
|
||||
|
||||
var refreshColumnObservers = function(){
|
||||
columns.children().each(function(){
|
||||
registerTweetObserverForColumn($(this));
|
||||
});
|
||||
};
|
||||
|
||||
new MutationObserver(refreshColumnObservers).observe(columns[0],{
|
||||
childList: true
|
||||
});
|
||||
|
||||
refreshColumnObservers();
|
||||
})();
|
||||
|
||||
isInitialized = true;
|
||||
};
|
||||
|
||||
//
|
||||
// Function: Registers an observer to a TweetDeck column, which reports new tweets.
|
||||
//
|
||||
var registerTweetObserverForColumn = function(column){
|
||||
if (column[0].hasAttribute("data-tweetdick-observed"))return;
|
||||
|
||||
var mid = column;
|
||||
mid = mid.children().first();
|
||||
mid = mid.children().first();
|
||||
mid = mid.children(".js-column-content").first();
|
||||
mid = mid.children(".js-column-scroller").first();
|
||||
|
||||
var container = mid.children(".js-chirp-container").first();
|
||||
if (container.length == 0)return;
|
||||
|
||||
new MutationObserver(function(mutations){
|
||||
// TODO check if popups are enabled first
|
||||
|
||||
Array.prototype.forEach.call(mutations,function(mutation){
|
||||
Array.prototype.forEach.call(mutation.addedNodes,function(node){
|
||||
if (node.tagName != "ARTICLE")return;
|
||||
|
||||
onNewTweet(column,node);
|
||||
});
|
||||
});
|
||||
}).observe(container[0],{
|
||||
childList: true
|
||||
});
|
||||
|
||||
column[0].setAttribute("data-tweetdick-observed","");
|
||||
};
|
||||
|
||||
//
|
||||
// Function: Event callback for a new tweet.
|
||||
//
|
||||
var onNewTweet = function(column, tweet){
|
||||
var html = $(tweet.outerHTML);
|
||||
html.find("footer:first").remove();
|
||||
|
||||
$TD.onTweetPopup(html.html(),""); // TODO
|
||||
};
|
||||
|
||||
//
|
||||
// Function: Retrieves the font size using <html> class attribute.
|
||||
//
|
||||
var getFontSizeClass = function(){
|
||||
for(var index = 0; index < fontSizeClasses.length; index++){
|
||||
if (document.documentElement.classList.contains(fontSizeClasses[index])){
|
||||
return fontSizeClasses[index];
|
||||
}
|
||||
}
|
||||
|
||||
return fontSizeClasses[0];
|
||||
};
|
||||
|
||||
//
|
||||
// Function: Retrieves the tags to be put into <head> for notification HTML code.
|
||||
//
|
||||
var getNotificationHeadContents = function(){
|
||||
var tags = [];
|
||||
|
||||
$(document.head).children("link[rel='stylesheet'],meta[charset],meta[http-equiv]").each(function(){
|
||||
tags.push($(this)[0].outerHTML);
|
||||
});
|
||||
|
||||
return tags.join("");
|
||||
};
|
||||
|
||||
//
|
||||
// Block: Observe the app <div> element and initialize TweetDick whenever possible.
|
||||
//
|
||||
@ -48,4 +143,31 @@
|
||||
attributes: true,
|
||||
attributeFilter: [ "class" ]
|
||||
});
|
||||
|
||||
//
|
||||
// Block: Observe changes in <html> class to update font size.
|
||||
//
|
||||
new MutationObserver(function(mutations){
|
||||
var fsClass = getFontSizeClass();
|
||||
|
||||
if (fsClass != prevFontSizeClass){
|
||||
prevFontSizeClass = fsClass;
|
||||
$TD.loadFontSizeClass(fsClass);
|
||||
}
|
||||
}).observe(document.documentElement,{
|
||||
attributes: true,
|
||||
attributeFilter: [ "class" ]
|
||||
});
|
||||
|
||||
//
|
||||
// Block: Observe stylesheet swapping.
|
||||
//
|
||||
new MutationObserver(function(mutations){
|
||||
$TD.loadNotificationHeadContents(getNotificationHeadContents());
|
||||
}).observe(document.head.querySelector("[http-equiv='Default-Style']"),{
|
||||
attributes: true,
|
||||
attributeFilter: [ "content" ]
|
||||
});
|
||||
|
||||
$TD.loadNotificationHeadContents(getNotificationHeadContents());
|
||||
})($,$TD);
|
||||
|
@ -86,6 +86,13 @@
|
||||
<Compile Include="Core\FormBrowser.Designer.cs">
|
||||
<DependentUpon>FormBrowser.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Core\FormNotification.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Core\FormNotification.Designer.cs">
|
||||
<DependentUpon>FormNotification.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Core\Handling\TweetNotification.cs" />
|
||||
<Compile Include="Core\RichTextLabel.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
|
Loading…
Reference in New Issue
Block a user