1
0
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:
chylex 2016-04-11 00:37:28 +02:00
parent b9c93bfe20
commit 2834a9a443
7 changed files with 330 additions and 1 deletions

View File

@ -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
View 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
View 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;
}
}
}
}

View File

@ -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);
}

View 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();
}
}
}

View File

@ -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);

View File

@ -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>