1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-05-29 11:34:07 +02:00

Implement feature usage analytics

This commit is contained in:
chylex 2017-11-08 08:15:45 +01:00
parent 51f9ba3642
commit b81e7583eb
13 changed files with 153 additions and 25 deletions

View File

@ -319,6 +319,7 @@ protected override void WndProc(ref Message m){
} }
else{ else{
browser.OnMouseClickExtra(m.WParam); browser.OnMouseClickExtra(m.WParam);
TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserExtraMouseButton);
} }
return; return;
@ -327,7 +328,7 @@ protected override void WndProc(ref Message m){
base.WndProc(ref m); base.WndProc(ref m);
} }
// notification helpers // bridge methods
public void PauseNotification(){ public void PauseNotification(){
notification.PauseNotification(); notification.PauseNotification();
@ -336,9 +337,7 @@ public void PauseNotification(){
public void ResumeNotification(){ public void ResumeNotification(){
notification.ResumeNotification(); notification.ResumeNotification();
} }
// browser bridge methods
public void ReinjectCustomCSS(string css){ public void ReinjectCustomCSS(string css){
browser.ReinjectCustomCSS(css); browser.ReinjectCustomCSS(css);
} }
@ -355,6 +354,10 @@ public void ApplyROT13(){
browser.ApplyROT13(); browser.ApplyROT13();
} }
public void TriggerAnalyticsEvent(AnalyticsFile.Event e){
analytics?.TriggerEvent(e);
}
// callback handlers // callback handlers
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){ public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
@ -423,19 +426,22 @@ public void OpenSettings(Type startTab){
notification.RequiresResize = true; notification.RequiresResize = true;
form.Dispose(); form.Dispose();
}; };
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenOptions);
ShowChildForm(form); ShowChildForm(form);
} }
} }
public void OpenAbout(){ public void OpenAbout(){
if (!FormManager.TryBringToFront<FormAbout>()){ if (!FormManager.TryBringToFront<FormAbout>()){
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenAbout);
ShowChildForm(new FormAbout()); ShowChildForm(new FormAbout());
} }
} }
public void OpenPlugins(){ public void OpenPlugins(){
if (!FormManager.TryBringToFront<FormPlugins>()){ if (!FormManager.TryBringToFront<FormPlugins>()){
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenPlugins);
ShowChildForm(new FormPlugins(plugins)); ShowChildForm(new FormPlugins(plugins));
} }
} }
@ -458,6 +464,8 @@ public void PlayNotificationSound(){
soundNotification.SetVolume(Config.NotificationSoundVolume); soundNotification.SetVolume(Config.NotificationSoundVolume);
soundNotification.Play(Config.NotificationSoundPath); soundNotification.Play(Config.NotificationSoundPath);
TriggerAnalyticsEvent(AnalyticsFile.Event.SoundNotification);
} }
public void PlayVideo(string url, string username){ public void PlayVideo(string url, string username){
@ -475,6 +483,7 @@ public void PlayVideo(string url, string username){
} }
videoPlayer.Launch(url, username); videoPlayer.Launch(url, username);
TriggerAnalyticsEvent(AnalyticsFile.Event.VideoPlay);
} }
public bool ProcessBrowserKey(Keys key){ public bool ProcessBrowserKey(Keys key){
@ -496,6 +505,7 @@ public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl)
notification.FinishCurrentNotification(); notification.FinishCurrentNotification();
browser.ShowTweetDetail(columnId, chirpId, fallbackUrl); browser.ShowTweetDetail(columnId, chirpId, fallbackUrl);
TriggerAnalyticsEvent(AnalyticsFile.Event.TweetDetail);
} }
public void OnTweetScreenshotReady(string html, int width, int height){ public void OnTweetScreenshotReady(string html, int width, int height){
@ -504,6 +514,7 @@ public void OnTweetScreenshotReady(string html, int width, int height){
} }
notificationScreenshotManager.Trigger(html, width, height); notificationScreenshotManager.Trigger(html, width, height);
TriggerAnalyticsEvent(AnalyticsFile.Event.TweetScreenshot);
} }
public void DisplayTooltip(string text){ public void DisplayTooltip(string text){

View File

@ -2,6 +2,7 @@
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
@ -95,6 +96,8 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
} }
RemoveSeparatorIfLast(model); RemoveSeparatorIfLast(model);
form.InvokeAsyncSafe(() => form.TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserContextMenu));
} }
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
@ -163,6 +166,7 @@ public static ContextMenu CreateMenu(FormBrowser form){
menu.Popup += (sender, args) => { menu.Popup += (sender, args) => {
menu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications; menu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications;
form.TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserContextMenu);
}; };
return menu; return menu;

View File

@ -1,6 +1,7 @@
using CefSharp; using CefSharp;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Analytics;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
sealed class ContextMenuNotification : ContextMenuBase{ sealed class ContextMenuNotification : ContextMenuBase{
@ -54,7 +55,10 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
RemoveSeparatorIfLast(model); RemoveSeparatorIfLast(model);
form.InvokeAsyncSafe(() => form.ContextMenuOpen = true); form.InvokeAsyncSafe(() => {
form.ContextMenuOpen = true;
form.TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationContextMenu);
});
} }
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){

View File

@ -2,6 +2,7 @@
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Analytics;
namespace TweetDuck.Core.Handling { namespace TweetDuck.Core.Handling {
sealed class KeyboardHandlerNotification : IKeyboardHandler{ sealed class KeyboardHandlerNotification : IKeyboardHandler{
@ -11,19 +12,26 @@ public KeyboardHandlerNotification(FormNotificationBase notification){
this.notification = notification; this.notification = notification;
} }
private void TriggerKeyboardShortcutAnalytics(){
notification.InvokeAsyncSafe(() => notification.TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationKeyboardShortcut));
}
bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut){ bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut){
if (type == KeyType.RawKeyDown && !browser.FocusedFrame.Url.StartsWith("chrome-devtools://")){ if (type == KeyType.RawKeyDown && !browser.FocusedFrame.Url.StartsWith("chrome-devtools://")){
switch((Keys)windowsKeyCode){ switch((Keys)windowsKeyCode){
case Keys.Enter: case Keys.Enter:
notification.InvokeAsyncSafe(notification.FinishCurrentNotification); notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
TriggerKeyboardShortcutAnalytics();
return true; return true;
case Keys.Escape: case Keys.Escape:
notification.InvokeAsyncSafe(notification.HideNotification); notification.InvokeAsyncSafe(notification.HideNotification);
TriggerKeyboardShortcutAnalytics();
return true; return true;
case Keys.Space: case Keys.Space:
notification.InvokeAsyncSafe(() => notification.FreezeTimer = !notification.FreezeTimer); notification.InvokeAsyncSafe(() => notification.FreezeTimer = !notification.FreezeTimer);
TriggerKeyboardShortcutAnalytics();
return true; return true;
} }
} }

View File

@ -8,6 +8,7 @@
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General; using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Other.Management; using TweetDuck.Core.Other.Management;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
@ -158,6 +159,10 @@ protected override void WndProc(ref Message m){
base.WndProc(ref m); base.WndProc(ref m);
} }
public void TriggerAnalyticsEvent(AnalyticsFile.Event e){
owner.TriggerAnalyticsEvent(e);
}
// event handlers // event handlers
private void owner_FormClosed(object sender, FormClosedEventArgs e){ private void owner_FormClosed(object sender, FormClosedEventArgs e){

View File

@ -5,6 +5,7 @@
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Data; using TweetDuck.Data;
using TweetDuck.Plugins; using TweetDuck.Plugins;
@ -127,6 +128,7 @@ private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
} }
blockXButtonUp = true; blockXButtonUp = true;
this.InvokeAsyncSafe(() => TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationExtraMouseButton));
return NativeMethods.HOOK_HANDLED; return NativeMethods.HOOK_HANDLED;
} }
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){ else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){

View File

@ -3,6 +3,7 @@
using System.Drawing; using System.Drawing;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
@ -93,6 +94,7 @@ public override void ShowNotification(TweetNotification notification){
} }
needsTrim |= tweetQueue.Count >= TrimMinimum; needsTrim |= tweetQueue.Count >= TrimMinimum;
TriggerAnalyticsEvent(AnalyticsFile.Event.DesktopNotification);
} }
public override void HideNotification(){ public override void HideNotification(){

View File

@ -12,12 +12,41 @@ static AnalyticsFile(){
}); });
} }
public enum Event{
OpenOptions, OpenPlugins, OpenAbout, OpenGuide,
DesktopNotification, SoundNotification,
BrowserContextMenu, BrowserExtraMouseButton,
NotificationContextMenu, NotificationExtraMouseButton, NotificationKeyboardShortcut,
TweetScreenshot, TweetDetail, VideoPlay, GCReload
}
// STATE PROPERTIES // STATE PROPERTIES
public DateTime LastDataCollection { get; set; } = DateTime.MinValue; public DateTime LastDataCollection { get; set; } = DateTime.MinValue;
public string LastCollectionVersion { get; set; } = null; public string LastCollectionVersion { get; set; } = null;
public string LastCollectionMessage { get; set; } = null; public string LastCollectionMessage { get; set; } = null;
// USAGE DATA
public int CountOpenOptions { get; private set; } = 0;
public int CountOpenPlugins { get; private set; } = 0;
public int CountOpenAbout { get; private set; } = 0;
public int CountOpenGuide { get; private set; } = 0;
public int CountDesktopNotifications { get; private set; } = 0;
public int CountSoundNotifications { get; private set; } = 0;
public int CountBrowserContextMenus { get; private set; } = 0;
public int CountBrowserExtraMouseButtons { get; private set; } = 0;
public int CountNotificationContextMenus { get; private set; } = 0;
public int CountNotificationExtraMouseButtons { get; private set; } = 0;
public int CountNotificationKeyboardShortcuts { get; private set; } = 0;
public int CountTweetScreenshots { get; private set; } = 0;
public int CountTweetDetails { get; private set; } = 0;
public int CountVideoPlays { get; private set; } = 0;
public int CountGCReloads { get; private set; } = 0;
// END OF DATA // END OF DATA
private readonly string file; private readonly string file;
@ -26,6 +55,29 @@ private AnalyticsFile(string file){
this.file = file; this.file = file;
} }
public void TriggerEvent(Event e){
switch(e){
case Event.OpenOptions: ++CountOpenOptions; break;
case Event.OpenPlugins: ++CountOpenPlugins; break;
case Event.OpenAbout: ++CountOpenAbout; break;
case Event.OpenGuide: ++CountOpenGuide; break;
case Event.DesktopNotification: ++CountDesktopNotifications; break;
case Event.SoundNotification: ++CountSoundNotifications; break;
case Event.BrowserContextMenu: ++CountBrowserContextMenus; break;
case Event.BrowserExtraMouseButton: ++CountBrowserExtraMouseButtons; break;
case Event.NotificationContextMenu: ++CountNotificationContextMenus; break;
case Event.NotificationExtraMouseButton: ++CountNotificationExtraMouseButtons; break;
case Event.NotificationKeyboardShortcut: ++CountNotificationKeyboardShortcuts; break;
case Event.TweetScreenshot: ++CountTweetScreenshots; break;
case Event.TweetDetail: ++CountTweetDetails; break;
case Event.VideoPlay: ++CountVideoPlays; break;
case Event.GCReload: ++CountGCReloads; break;
}
}
public void Save(){ public void Save(){
try{ try{
Serializer.Write(file, this); Serializer.Write(file, this);

View File

@ -11,22 +11,24 @@ sealed class AnalyticsManager : IDisposable{
private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(7); private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(7);
private static readonly Uri CollectionUrl = new Uri("https://tweetduck.chylex.com/breadcrumb/report"); private static readonly Uri CollectionUrl = new Uri("https://tweetduck.chylex.com/breadcrumb/report");
public string LastCollectionMessage => file.LastCollectionMessage; public AnalyticsFile File { get; }
private readonly FormBrowser browser; private readonly FormBrowser browser;
private readonly PluginManager plugins; private readonly PluginManager plugins;
private readonly AnalyticsFile file; private readonly Timer currentTimer, saveTimer;
private readonly Timer currentTimer;
public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file){ public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file){
this.browser = browser; this.browser = browser;
this.plugins = plugins; this.plugins = plugins;
this.file = AnalyticsFile.Load(file); this.File = AnalyticsFile.Load(file);
this.currentTimer = new Timer{ SynchronizingObject = browser }; this.currentTimer = new Timer{ SynchronizingObject = browser };
this.currentTimer.Elapsed += currentTimer_Elapsed; this.currentTimer.Elapsed += currentTimer_Elapsed;
if (this.file.LastCollectionVersion != Program.VersionTag){ this.saveTimer = new Timer{ SynchronizingObject = browser, Interval = 60000 };
this.saveTimer.Elapsed += saveTimer_Elapsed;
if (this.File.LastCollectionVersion != Program.VersionTag){
ScheduleReportIn(TimeSpan.FromHours(12), string.Empty); ScheduleReportIn(TimeSpan.FromHours(12), string.Empty);
} }
else{ else{
@ -35,7 +37,22 @@ public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file)
} }
public void Dispose(){ public void Dispose(){
if (saveTimer.Enabled){
File.Save();
}
currentTimer.Dispose(); currentTimer.Dispose();
saveTimer.Dispose();
}
public void TriggerEvent(AnalyticsFile.Event e){
File.TriggerEvent(e);
saveTimer.Enabled = true;
}
private void saveTimer_Elapsed(object sender, ElapsedEventArgs e){
saveTimer.Stop();
File.Save();
} }
private void ScheduleReportIn(TimeSpan delay, string message = null){ private void ScheduleReportIn(TimeSpan delay, string message = null){
@ -43,16 +60,16 @@ private void ScheduleReportIn(TimeSpan delay, string message = null){
} }
private void SetLastDataCollectionTime(DateTime dt, string message = null){ private void SetLastDataCollectionTime(DateTime dt, string message = null){
file.LastDataCollection = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0, dt.Kind); File.LastDataCollection = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0, dt.Kind);
file.LastCollectionVersion = Program.VersionTag; File.LastCollectionVersion = Program.VersionTag;
file.LastCollectionMessage = message ?? dt.ToString("g", Program.Culture); File.LastCollectionMessage = message ?? dt.ToString("g", Program.Culture);
file.Save(); File.Save();
RestartTimer(); RestartTimer();
} }
private void RestartTimer(){ private void RestartTimer(){
TimeSpan diff = DateTime.Now.Subtract(file.LastDataCollection); TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
int minutesTillNext = (int)(CollectionInterval.TotalMinutes-Math.Floor(diff.TotalMinutes)); int minutesTillNext = (int)(CollectionInterval.TotalMinutes-Math.Floor(diff.TotalMinutes));
currentTimer.Interval = Math.Max(minutesTillNext, 1)*60000; currentTimer.Interval = Math.Max(minutesTillNext, 1)*60000;
@ -62,7 +79,7 @@ private void RestartTimer(){
private void currentTimer_Elapsed(object sender, ElapsedEventArgs e){ private void currentTimer_Elapsed(object sender, ElapsedEventArgs e){
currentTimer.Stop(); currentTimer.Stop();
TimeSpan diff = DateTime.Now.Subtract(file.LastDataCollection); TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
if (Math.Floor(diff.TotalMinutes) >= CollectionInterval.TotalMinutes){ if (Math.Floor(diff.TotalMinutes) >= CollectionInterval.TotalMinutes){
SendReport(); SendReport();
@ -76,7 +93,7 @@ private void SendReport(){
AnalyticsReportGenerator.ExternalInfo info = AnalyticsReportGenerator.ExternalInfo.From(browser); AnalyticsReportGenerator.ExternalInfo info = AnalyticsReportGenerator.ExternalInfo.From(browser);
Task.Factory.StartNew(() => { Task.Factory.StartNew(() => {
AnalyticsReport report = AnalyticsReportGenerator.Create(info, plugins); AnalyticsReport report = AnalyticsReportGenerator.Create(File, info, plugins);
BrowserUtils.CreateWebClient().UploadValues(CollectionUrl, "POST", report.ToNameValueCollection()); BrowserUtils.CreateWebClient().UploadValues(CollectionUrl, "POST", report.ToNameValueCollection());
}).ContinueWith(task => browser.InvokeAsyncSafe(() => { }).ContinueWith(task => browser.InvokeAsyncSafe(() => {
if (task.Status == TaskStatus.RanToCompletion){ if (task.Status == TaskStatus.RanToCompletion){

View File

@ -14,7 +14,7 @@
namespace TweetDuck.Core.Other.Analytics{ namespace TweetDuck.Core.Other.Analytics{
static class AnalyticsReportGenerator{ static class AnalyticsReportGenerator{
public static AnalyticsReport Create(ExternalInfo info, PluginManager plugins){ public static AnalyticsReport Create(AnalyticsFile file, ExternalInfo info, PluginManager plugins){
Dictionary<string, string> editLayoutDesign = EditLayoutDesignPluginData; Dictionary<string, string> editLayoutDesign = EditLayoutDesignPluginData;
return new AnalyticsReport{ return new AnalyticsReport{
@ -84,6 +84,22 @@ public static AnalyticsReport Create(ExternalInfo info, PluginManager plugins){
{ "Optimize Animations" , Dict(editLayoutDesign, "optimizeAnimations", "true/def") }, { "Optimize Animations" , Dict(editLayoutDesign, "optimizeAnimations", "true/def") },
{ "Reply Account Mode" , ReplyAccountConfigFromPlugin }, { "Reply Account Mode" , ReplyAccountConfigFromPlugin },
{ "Template Count" , Exact(TemplateCountFromPlugin) }, { "Template Count" , Exact(TemplateCountFromPlugin) },
0,
{ "Opened Options" , LogRound(file.CountOpenOptions, 4) },
{ "Opened Plugins" , LogRound(file.CountOpenPlugins, 4) },
{ "Opened About" , LogRound(file.CountOpenAbout, 4) },
{ "Opened Guide" , LogRound(file.CountOpenGuide, 4) },
{ "Desktop Notifications" , LogRound(file.CountDesktopNotifications, 5) },
{ "Sound Notifications" , LogRound(file.CountSoundNotifications, 5) },
{ "Browser Context Menus" , LogRound(file.CountBrowserContextMenus, 2) },
{ "Browser Extra Mouse Buttons" , LogRound(file.CountBrowserExtraMouseButtons, 2) },
{ "Notification Context Menus" , LogRound(file.CountNotificationContextMenus, 2) },
{ "Notification Extra Mouse Buttons" , LogRound(file.CountNotificationExtraMouseButtons, 2) },
{ "Notification Keyboard Shortcuts" , LogRound(file.CountNotificationKeyboardShortcuts, 2) },
{ "Tweet Screenshots" , LogRound(file.CountTweetScreenshots, 2) },
{ "Tweet Details" , LogRound(file.CountTweetDetails, 2) },
{ "Video Plays" , LogRound(file.CountVideoPlays, 4) },
{ "GC Reloads" , LogRound(file.CountGCReloads, 4) }
}.FinalizeReport(); }.FinalizeReport();
} }
@ -93,6 +109,7 @@ public static AnalyticsReport Create(ExternalInfo info, PluginManager plugins){
private static string Bool(bool value) => value ? "on" : "off"; private static string Bool(bool value) => value ? "on" : "off";
private static string Exact(int value) => value.ToString(); private static string Exact(int value) => value.ToString();
private static string RoundUp(int value, int multiple) => (multiple*(int)Math.Ceiling((double)value/multiple)).ToString(); private static string RoundUp(int value, int multiple) => (multiple*(int)Math.Ceiling((double)value/multiple)).ToString();
private static string LogRound(int value, int logBase) => (value <= 0 ? 0 : (int)Math.Pow(logBase, Math.Floor(Math.Log(value, logBase)))).ToString();
private static string Dict(Dictionary<string, string> dict, string key, string def = "(unknown)") => dict.TryGetValue(key, out string value) ? value : def; private static string Dict(Dictionary<string, string> dict, string key, string def = "(unknown)") => dict.TryGetValue(key, out string value) ? value : def;
private static string List(IEnumerable<string> list) => string.Join("|", list.DefaultIfEmpty("(none)")); private static string List(IEnumerable<string> list) => string.Join("|", list.DefaultIfEmpty("(none)"));

View File

@ -6,6 +6,7 @@
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General; using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
@ -24,6 +25,8 @@ public FormGuide(){
if (owner != null){ if (owner != null){
Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4); Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4);
VisibleChanged += (sender, args) => this.MoveToCenter(owner); VisibleChanged += (sender, args) => this.MoveToCenter(owner);
owner.TriggerAnalyticsEvent(AnalyticsFile.Event.OpenGuide);
} }
this.browser = new ChromiumWebBrowser(GuideUrl){ this.browser = new ChromiumWebBrowser(GuideUrl){

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Timers; using System.Timers;
using System.Windows.Forms;
using CefSharp; using CefSharp;
using CefSharp.WinForms; using CefSharp.WinForms;
using TweetDuck.Core.Controls;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
namespace TweetDuck.Core.Other.Management{ namespace TweetDuck.Core.Other.Management{
@ -13,7 +13,7 @@ sealed class MemoryUsageTracker : IDisposable{
private readonly string script; private readonly string script;
private readonly Timer timer; private readonly Timer timer;
private Form owner; private FormBrowser owner;
private IBrowser browser; private IBrowser browser;
private long threshold; private long threshold;
@ -29,7 +29,7 @@ public MemoryUsageTracker(string cleanupFunctionName){
public void Start(ChromiumWebBrowser control, int thresholdMB){ public void Start(ChromiumWebBrowser control, int thresholdMB){
Stop(); Stop();
this.owner = (Form)control.Parent; // TODO ugly this.owner = (FormBrowser)control.Parent; // TODO ugly
this.browser = control.GetBrowser(); this.browser = control.GetBrowser();
this.threshold = thresholdMB*1024L*1024L; this.threshold = thresholdMB*1024L*1024L;
this.timer.SynchronizingObject = owner; this.timer.SynchronizingObject = owner;
@ -71,6 +71,7 @@ private void timer_Elapsed(object sender, ElapsedEventArgs e){
if (response.Success && (response.Result as bool? ?? false)){ if (response.Success && (response.Result as bool? ?? false)){
SetNeedsCleanup(false); SetNeedsCleanup(false);
owner.InvokeAsyncSafe(() => owner.TriggerAnalyticsEvent(Analytics.AnalyticsFile.Event.GCReload));
} }
}); });
} }

View File

@ -7,19 +7,21 @@
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsFeedback : BaseTabSettings{ sealed partial class TabSettingsFeedback : BaseTabSettings{
private readonly AnalyticsFile analyticsFile;
private readonly AnalyticsReportGenerator.ExternalInfo analyticsInfo; private readonly AnalyticsReportGenerator.ExternalInfo analyticsInfo;
private readonly PluginManager plugins; private readonly PluginManager plugins;
public TabSettingsFeedback(AnalyticsManager analytics, AnalyticsReportGenerator.ExternalInfo analyticsInfo, PluginManager plugins){ public TabSettingsFeedback(AnalyticsManager analytics, AnalyticsReportGenerator.ExternalInfo analyticsInfo, PluginManager plugins){
InitializeComponent(); InitializeComponent();
this.analyticsFile = analytics?.File ?? AnalyticsFile.Load(Program.AnalyticsFilePath);
this.analyticsInfo = analyticsInfo; this.analyticsInfo = analyticsInfo;
this.plugins = plugins; this.plugins = plugins;
checkDataCollection.Checked = Config.AllowDataCollection; checkDataCollection.Checked = Config.AllowDataCollection;
if (analytics != null){ if (analytics != null){
string collectionTime = analytics.LastCollectionMessage; string collectionTime = analyticsFile.LastCollectionMessage;
labelDataCollectionMessage.Text = string.IsNullOrEmpty(collectionTime) ? "No collection yet" : "Last collection: "+collectionTime; labelDataCollectionMessage.Text = string.IsNullOrEmpty(collectionTime) ? "No collection yet" : "Last collection: "+collectionTime;
} }
} }
@ -44,7 +46,7 @@ private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkCli
} }
private void btnViewReport_Click(object sender, EventArgs e){ private void btnViewReport_Click(object sender, EventArgs e){
using(DialogSettingsAnalytics dialog = new DialogSettingsAnalytics(AnalyticsReportGenerator.Create(analyticsInfo, plugins))){ using(DialogSettingsAnalytics dialog = new DialogSettingsAnalytics(AnalyticsReportGenerator.Create(analyticsFile, analyticsInfo, plugins))){
dialog.ShowDialog(); dialog.ShowDialog();
} }
} }