1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-02-27 14:46:02 +01:00

Remove analytics

This commit is contained in:
chylex 2021-12-17 03:29:28 +01:00
parent b18cd2658c
commit 763c999b09
Signed by: chylex
GPG Key ID: 4DE42C8F19A80548
28 changed files with 78 additions and 1095 deletions

View File

@ -41,8 +41,8 @@ public void OpenProfileImport() {
form.InvokeAsyncSafe(form.OpenProfileImport);
}
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection) {
form.InvokeAsyncSafe(() => form.OnIntroductionClosed(showGuide, allowDataCollection));
public void OnIntroductionClosed(bool showGuide) {
form.InvokeAsyncSafe(() => form.OnIntroductionClosed(showGuide));
}
public void LoadNotificationLayout(string fontSize, string headLayout) {

View File

@ -15,7 +15,6 @@
using TweetDuck.Dialogs;
using TweetDuck.Dialogs.Settings;
using TweetDuck.Management;
using TweetDuck.Management.Analytics;
using TweetDuck.Plugins;
using TweetDuck.Updates;
using TweetDuck.Utils;
@ -24,7 +23,7 @@
using TweetLib.Core.Systems.Updates;
namespace TweetDuck.Browser {
sealed partial class FormBrowser : Form, AnalyticsFile.IProvider {
sealed partial class FormBrowser : Form {
private static UserConfig Config => Program.Config.User;
public bool IsWaiting {
@ -47,8 +46,6 @@ public bool IsWaiting {
public UpdateInstaller UpdateInstaller { get; private set; }
private bool ignoreUpdateCheckError;
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
#pragma warning disable IDE0069 // Disposable fields should be disposed
private readonly TweetDeckBrowser browser;
private readonly FormNotificationTweet notification;
@ -64,7 +61,6 @@ public bool IsWaiting {
private TweetScreenshotManager notificationScreenshotManager;
private VideoPlayer videoPlayer;
private AnalyticsManager analytics;
public FormBrowser(PluginSchemeFactory pluginScheme) {
InitializeComponent();
@ -110,10 +106,6 @@ public FormBrowser(PluginSchemeFactory pluginScheme) {
UpdateFormIcon();
}
if (Config.AllowDataCollection) {
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
RestoreWindow();
}
@ -126,7 +118,6 @@ protected override void Dispose(bool disposing) {
notificationScreenshotManager?.Dispose();
videoPlayer?.Dispose();
analytics?.Dispose();
}
base.Dispose(disposing);
@ -243,7 +234,6 @@ private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e) {
private void Config_MuteToggled(object sender, EventArgs e) {
UpdateFormIcon();
AnalyticsFile.NotificationMutes.Trigger();
}
private void Config_TrayBehaviorChanged(object sender, EventArgs e) {
@ -368,7 +358,6 @@ protected override void WndProc(ref Message m) {
}
else {
browser.OnMouseClickExtra(m.WParam);
AnalyticsFile.BrowserExtraMouseButtons.Trigger();
}
return;
@ -395,7 +384,6 @@ public void ReloadToTweetDeck() {
Program.Resources.OnReloadTriggered();
ignoreUpdateCheckError = false;
browser.ReloadToTweetDeck();
AnalyticsFile.BrowserReloads.Trigger();
}
public void AddSearchColumn(string query) {
@ -416,7 +404,6 @@ public void PlaySoundNotification() {
public void ApplyROT13() {
browser.ApplyROT13();
AnalyticsFile.UsedROT13.Trigger();
}
public void OpenDevTools() {
@ -425,15 +412,10 @@ public void OpenDevTools() {
// callback handlers
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection) {
public void OnIntroductionClosed(bool showGuide) {
if (Config.FirstRun) {
Config.FirstRun = false;
Config.AllowDataCollection = allowDataCollection;
Config.Save();
if (allowDataCollection && analytics == null) {
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
}
if (showGuide) {
@ -453,7 +435,7 @@ public void OpenSettings(Type startTab) {
if (!FormManager.TryBringToFront<FormSettings>()) {
bool prevEnableUpdateCheck = Config.EnableUpdateCheck;
FormSettings form = new FormSettings(this, plugins, updates, analytics, startTab);
FormSettings form = new FormSettings(this, plugins, updates, startTab);
form.FormClosed += (sender, args) => {
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck) {
@ -467,14 +449,6 @@ public void OpenSettings(Type startTab) {
trayIcon.HasNotifications = false;
}
if (Config.AllowDataCollection) {
analytics ??= new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
else if (analytics != null) {
analytics.Dispose();
analytics = null;
}
BrowserCache.RefreshTimer();
if (form.ShouldReloadBrowser) {
@ -489,21 +463,18 @@ public void OpenSettings(Type startTab) {
form.Dispose();
};
AnalyticsFile.OpenOptions.Trigger();
ShowChildForm(form);
}
}
public void OpenAbout() {
if (!FormManager.TryBringToFront<FormAbout>()) {
AnalyticsFile.OpenAbout.Trigger();
ShowChildForm(new FormAbout());
}
}
public void OpenPlugins() {
if (!FormManager.TryBringToFront<FormPlugins>()) {
AnalyticsFile.OpenPlugins.Trigger();
ShowChildForm(new FormPlugins(plugins));
}
}
@ -526,9 +497,7 @@ public void OpenProfileImport() {
}
}
public void OnTweetSound() {
AnalyticsFile.SoundNotifications.Trigger();
}
public void OnTweetSound() {}
public void PlayVideo(string videoUrl, string tweetUrl, string username, IJavascriptCallback callShowOverlay) {
string playerPath = Config.VideoPlayerPath;
@ -556,8 +525,6 @@ public void PlayVideo(string videoUrl, string tweetUrl, string username, IJavasc
Program.Reporter.HandleException("Error Opening Video Player", "Could not open the video player.", true, e);
}
}
AnalyticsFile.VideoPlays.Trigger();
}
public void StopVideo() {
@ -583,13 +550,11 @@ public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl)
notification.FinishCurrentNotification();
browser.ShowTweetDetail(columnId, chirpId, fallbackUrl);
AnalyticsFile.TweetDetails.Trigger();
}
public void OnTweetScreenshotReady(string html, int width) {
notificationScreenshotManager ??= new TweetScreenshotManager(this, plugins);
notificationScreenshotManager.Trigger(html, width);
AnalyticsFile.TweetScreenshots.Trigger();
}
public void DisplayTooltip(string text) {

View File

@ -10,7 +10,6 @@
using TweetDuck.Controls;
using TweetDuck.Dialogs;
using TweetDuck.Management;
using TweetDuck.Management.Analytics;
using TweetDuck.Utils;
using TweetLib.Core.Features.Twitter;
using TweetLib.Core.Utils;
@ -37,12 +36,6 @@ abstract class ContextMenuBase : IContextMenuHandler {
protected ContextInfo.ContextData Context { get; private set; }
private readonly AnalyticsFile.IProvider analytics;
protected ContextMenuBase(AnalyticsFile.IProvider analytics) {
this.analytics = analytics;
}
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) {
if (!TwitterUrls.IsTweetDeck(frame.Url) || browser.IsLoading) {
Context = CurrentInfo.Reset();
@ -114,7 +107,6 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
Match match = TwitterUrls.RegexAccount.Match(url);
SetClipboardText(control, match.Success ? match.Groups[1].Value : url);
control.InvokeAsyncSafe(analytics.AnalyticsFile.CopiedUsernames.Trigger);
break;
}
@ -139,7 +131,6 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
control.InvokeAsyncSafe(() => {
TwitterUtils.ViewImage(url, ImageQuality);
analytics.AnalyticsFile.ViewedImages.Trigger();
});
break;
@ -153,11 +144,9 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
control.InvokeAsyncSafe(() => {
if (isVideo) {
TwitterUtils.DownloadVideo(url, username);
analytics.AnalyticsFile.DownloadedVideos.Trigger();
}
else {
TwitterUtils.DownloadImage(url, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
}
});
@ -170,7 +159,6 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
control.InvokeAsyncSafe(() => {
TwitterUtils.DownloadImages(urls, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
});
break;
@ -179,7 +167,6 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
case MenuReadApplyROT13:
string selection = parameters.SelectionText;
control.InvokeAsyncSafe(() => FormMessage.Information("ROT13", StringUtils.ConvertRot13(selection), FormMessage.OK));
control.InvokeAsyncSafe(analytics.AnalyticsFile.UsedROT13.Trigger);
return true;
case MenuSearchInBrowser:

View File

@ -28,7 +28,7 @@ sealed class ContextMenuBrowser : ContextMenuBase {
private readonly FormBrowser form;
public ContextMenuBrowser(FormBrowser form) : base(form) {
public ContextMenuBrowser(FormBrowser form) {
this.form = form;
}
@ -89,8 +89,6 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
}
RemoveSeparatorIfLast(model);
form.InvokeAsyncSafe(form.AnalyticsFile.BrowserContextMenus.Trigger);
}
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags) {
@ -165,7 +163,6 @@ public static ContextMenu CreateMenu(FormBrowser form) {
menu.Popup += (sender, args) => {
menu.MenuItems[1].Checked = Config.MuteNotifications;
form.AnalyticsFile.BrowserContextMenus.Trigger();
};
return menu;

View File

@ -1,10 +1,7 @@
using CefSharp;
using TweetDuck.Management.Analytics;
namespace TweetDuck.Browser.Handling {
sealed class ContextMenuGuide : ContextMenuBase {
public ContextMenuGuide(AnalyticsFile.IProvider analytics) : base(analytics) {}
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) {
model.Clear();
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);

View File

@ -13,7 +13,7 @@ sealed class ContextMenuNotification : ContextMenuBase {
private readonly FormNotificationBase form;
private readonly bool enableCustomMenu;
public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu) : base(form) {
public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu) {
this.form = form;
this.enableCustomMenu = enableCustomMenu;
}
@ -52,7 +52,6 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
form.InvokeAsyncSafe(() => {
form.ContextMenuOpen = true;
form.AnalyticsFile.NotificationContextMenus.Trigger();
});
}

View File

@ -11,10 +11,6 @@ public KeyboardHandlerNotification(FormNotificationBase notification) {
this.notification = notification;
}
private void TriggerKeyboardShortcutAnalytics() {
notification.InvokeAsyncSafe(notification.AnalyticsFile.NotificationKeyboardShortcuts.Trigger);
}
protected override bool HandleRawKey(IWebBrowser browserControl, Keys key, CefEventFlags modifiers) {
if (base.HandleRawKey(browserControl, key, modifiers)) {
return true;
@ -23,17 +19,14 @@ protected override bool HandleRawKey(IWebBrowser browserControl, Keys key, CefEv
switch (key) {
case Keys.Enter:
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
TriggerKeyboardShortcutAnalytics();
return true;
case Keys.Escape:
notification.InvokeAsyncSafe(notification.HideNotification);
TriggerKeyboardShortcutAnalytics();
return true;
case Keys.Space:
notification.InvokeAsyncSafe(() => notification.FreezeTimer = !notification.FreezeTimer);
TriggerKeyboardShortcutAnalytics();
return true;
default:

View File

@ -6,13 +6,12 @@
using TweetDuck.Browser.Handling.General;
using TweetDuck.Configuration;
using TweetDuck.Controls;
using TweetDuck.Management.Analytics;
using TweetDuck.Utils;
using TweetLib.Core.Features.Notifications;
using TweetLib.Core.Features.Twitter;
namespace TweetDuck.Browser.Notification {
abstract partial class FormNotificationBase : Form, AnalyticsFile.IProvider {
abstract partial class FormNotificationBase : Form {
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandlers.ForBytes(Properties.Resources.avatar, "image/png"));
protected const string BlankURL = TwitterUrls.TweetDeck + "/?blank";
@ -94,8 +93,6 @@ protected virtual FormBorderStyle NotificationBorderStyle {
}
}
public AnalyticsFile AnalyticsFile => owner.AnalyticsFile;
protected override bool ShowWithoutActivation => true;
protected float DpiScale { get; }

View File

@ -134,7 +134,6 @@ private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) {
}
blockXButtonUp = true;
this.InvokeAsyncSafe(AnalyticsFile.NotificationExtraMouseButtons.Trigger);
return NativeMethods.HOOK_HANDLED;
}
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp) {

View File

@ -94,7 +94,6 @@ public override void ShowNotification(DesktopNotification notification) {
}
needsTrim |= tweetQueue.Count >= TrimMinimum;
AnalyticsFile.DesktopNotifications.Trigger();
}
public override void HideNotification() {

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using TweetDuck.Browser;
using TweetDuck.Browser.Data;
@ -12,6 +13,8 @@ sealed class UserConfig : BaseConfig {
// CONFIGURATION DATA
public bool FirstRun { get; set; } = true;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public bool AllowDataCollection { get; set; } = false;
public WindowState BrowserWindow { get; set; } = new WindowState();

View File

@ -46,7 +46,6 @@ public static void Show(string hash = null) {
FormBrowser owner = FormManager.TryFind<FormBrowser>();
if (owner != null) {
owner.AnalyticsFile.OpenGuide.Trigger();
new FormGuide(url, owner).Show(owner);
}
}
@ -73,7 +72,7 @@ private FormGuide(string url, FormBrowser owner) {
resourceRequestHandler.ResourceHandlers.Register(DummyPage);
this.browser = new ChromiumWebBrowser(url) {
MenuHandler = new ContextMenuGuide(owner),
MenuHandler = new ContextMenuGuide(),
JsDialogHandler = new JavaScriptDialogHandler(),
KeyboardHandler = new KeyboardHandlerBase(),
LifeSpanHandler = new CustomLifeSpanHandler(),

View File

@ -9,7 +9,6 @@
using TweetDuck.Controls;
using TweetDuck.Dialogs.Settings;
using TweetDuck.Management;
using TweetDuck.Management.Analytics;
using TweetDuck.Utils;
using TweetLib.Core.Features.Plugins;
using TweetLib.Core.Systems.Updates;
@ -26,7 +25,7 @@ sealed partial class FormSettings : Form, FormManager.IAppDialog {
private readonly Dictionary<Type, SettingsTab> tabs = new Dictionary<Type, SettingsTab>(8);
private SettingsTab currentTab;
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, AnalyticsManager analytics, Type startTab) {
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, Type startTab) {
InitializeComponent();
Text = Program.BrandName + " Options";
@ -44,7 +43,7 @@ public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler up
AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins)));
AddButton("Sounds", () => new TabSettingsSounds(this.browser.PlaySoundNotification));
AddButton("Tray", () => new TabSettingsTray());
AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins));
AddButton("Feedback", () => new TabSettingsFeedback());
AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS, this.browser.OpenDevTools));
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);

View File

@ -1,94 +0,0 @@
namespace TweetDuck.Dialogs.Settings {
partial class DialogSettingsAnalytics {
/// <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.textBoxReport = new System.Windows.Forms.TextBox();
this.btnClose = new System.Windows.Forms.Button();
this.labelInfo = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// textBoxReport
//
this.textBoxReport.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBoxReport.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
this.textBoxReport.Location = new System.Drawing.Point(12, 45);
this.textBoxReport.Multiline = true;
this.textBoxReport.Name = "textBoxReport";
this.textBoxReport.ReadOnly = true;
this.textBoxReport.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxReport.Size = new System.Drawing.Size(435, 474);
this.textBoxReport.TabIndex = 1;
//
// btnClose
//
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.AutoSize = true;
this.btnClose.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnClose.Location = new System.Drawing.Point(397, 525);
this.btnClose.Name = "btnClose";
this.btnClose.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnClose.Size = new System.Drawing.Size(50, 25);
this.btnClose.TabIndex = 2;
this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// labelInfo
//
this.labelInfo.AutoSize = true;
this.labelInfo.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelInfo.Location = new System.Drawing.Point(12, 9);
this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
this.labelInfo.Name = "labelInfo";
this.labelInfo.Size = new System.Drawing.Size(434, 30);
this.labelInfo.TabIndex = 0;
this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly every 14 days." +
"\r\nSome numbers in the report were made imprecise on purpose.";
//
// DialogSettingsAnalytics
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(459, 562);
this.Controls.Add(this.labelInfo);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.textBoxReport);
this.MinimumSize = new System.Drawing.Size(475, 340);
this.Name = "DialogSettingsAnalytics";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBoxReport;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Label labelInfo;
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Windows.Forms;
using TweetDuck.Controls;
using TweetDuck.Management.Analytics;
namespace TweetDuck.Dialogs.Settings {
sealed partial class DialogSettingsAnalytics : Form {
public DialogSettingsAnalytics(AnalyticsReport report) {
InitializeComponent();
Text = Program.BrandName + " Options - Analytics Report";
textBoxReport.EnableMultilineShortcuts();
textBoxReport.Text = report.ToString().TrimEnd();
textBoxReport.Select(0, 0);
}
private void btnClose_Click(object sender, EventArgs e) {
Close();
}
}
}

View File

@ -1,11 +1,11 @@
namespace TweetDuck.Dialogs.Settings {
partial class TabSettingsFeedback {
/// <summary>
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
@ -18,165 +18,72 @@ protected override void Dispose(bool disposing) {
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// <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.panelDataCollection = new System.Windows.Forms.Panel();
this.labelDataCollectionLink = new System.Windows.Forms.LinkLabel();
this.checkDataCollection = new System.Windows.Forms.CheckBox();
this.labelDataCollectionMessage = new System.Windows.Forms.Label();
this.btnViewReport = new System.Windows.Forms.Button();
this.btnSendFeedback = new System.Windows.Forms.Button();
this.labelDataCollection = new System.Windows.Forms.Label();
this.labelFeedback = new System.Windows.Forms.Label();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.panelDataCollection.SuspendLayout();
this.flowPanel.SuspendLayout();
this.SuspendLayout();
//
// panelDataCollection
//
this.panelDataCollection.Controls.Add(this.labelDataCollectionLink);
this.panelDataCollection.Controls.Add(this.checkDataCollection);
this.panelDataCollection.Location = new System.Drawing.Point(0, 78);
this.panelDataCollection.Margin = new System.Windows.Forms.Padding(0);
this.panelDataCollection.Name = "panelDataCollection";
this.panelDataCollection.Size = new System.Drawing.Size(300, 28);
this.panelDataCollection.TabIndex = 3;
//
// labelDataCollectionLink
//
this.labelDataCollectionLink.AutoSize = true;
this.labelDataCollectionLink.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelDataCollectionLink.LinkArea = new System.Windows.Forms.LinkArea(1, 10);
this.labelDataCollectionLink.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
this.labelDataCollectionLink.Location = new System.Drawing.Point(153, 4);
this.labelDataCollectionLink.Margin = new System.Windows.Forms.Padding(0);
this.labelDataCollectionLink.Name = "labelDataCollectionLink";
this.labelDataCollectionLink.Size = new System.Drawing.Size(71, 21);
this.labelDataCollectionLink.TabIndex = 1;
this.labelDataCollectionLink.TabStop = true;
this.labelDataCollectionLink.Text = "(learn more)";
this.labelDataCollectionLink.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.labelDataCollectionLink.UseCompatibleTextRendering = true;
//
// checkDataCollection
//
this.checkDataCollection.AutoSize = true;
this.checkDataCollection.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkDataCollection.Location = new System.Drawing.Point(6, 6);
this.checkDataCollection.Margin = new System.Windows.Forms.Padding(6, 6, 0, 2);
this.checkDataCollection.Name = "checkDataCollection";
this.checkDataCollection.Size = new System.Drawing.Size(147, 19);
this.checkDataCollection.TabIndex = 0;
this.checkDataCollection.Text = "Send Anonymous Data";
this.checkDataCollection.UseVisualStyleBackColor = true;
//
// labelDataCollectionMessage
//
this.labelDataCollectionMessage.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelDataCollectionMessage.Location = new System.Drawing.Point(6, 143);
this.labelDataCollectionMessage.Margin = new System.Windows.Forms.Padding(6);
this.labelDataCollectionMessage.Name = "labelDataCollectionMessage";
this.labelDataCollectionMessage.Size = new System.Drawing.Size(288, 67);
this.labelDataCollectionMessage.TabIndex = 5;
//
// btnViewReport
//
this.btnViewReport.AutoSize = true;
this.btnViewReport.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnViewReport.Location = new System.Drawing.Point(5, 109);
this.btnViewReport.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnViewReport.Name = "btnViewReport";
this.btnViewReport.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnViewReport.Size = new System.Drawing.Size(155, 25);
this.btnViewReport.TabIndex = 4;
this.btnViewReport.Text = "View My Analytics Report";
this.btnViewReport.UseVisualStyleBackColor = true;
//
// btnSendFeedback
//
this.btnSendFeedback.AutoSize = true;
this.btnSendFeedback.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnSendFeedback.Location = new System.Drawing.Point(5, 23);
this.btnSendFeedback.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnSendFeedback.Name = "btnSendFeedback";
this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnSendFeedback.Size = new System.Drawing.Size(170, 25);
this.btnSendFeedback.TabIndex = 1;
this.btnSendFeedback.Text = "Send Feedback / Bug Report";
this.btnSendFeedback.UseVisualStyleBackColor = true;
//
// labelDataCollection
//
this.labelDataCollection.AutoSize = true;
this.labelDataCollection.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelDataCollection.Location = new System.Drawing.Point(3, 63);
this.labelDataCollection.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDataCollection.Name = "labelDataCollection";
this.labelDataCollection.Size = new System.Drawing.Size(88, 15);
this.labelDataCollection.TabIndex = 2;
this.labelDataCollection.Text = "Data Collection";
//
// labelFeedback
//
this.labelFeedback.AutoSize = true;
this.labelFeedback.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelFeedback.Location = new System.Drawing.Point(0, 0);
this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelFeedback.Name = "labelFeedback";
this.labelFeedback.Size = new System.Drawing.Size(75, 19);
this.labelFeedback.TabIndex = 0;
this.labelFeedback.Text = "FEEDBACK";
//
// flowPanel
//
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.flowPanel.Controls.Add(this.labelFeedback);
this.flowPanel.Controls.Add(this.btnSendFeedback);
this.flowPanel.Controls.Add(this.labelDataCollection);
this.flowPanel.Controls.Add(this.panelDataCollection);
this.flowPanel.Controls.Add(this.btnViewReport);
this.flowPanel.Controls.Add(this.labelDataCollectionMessage);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(300, 462);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
//
// TabSettingsFeedback
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.flowPanel);
this.Name = "TabSettingsFeedback";
this.Size = new System.Drawing.Size(631, 480);
this.panelDataCollection.ResumeLayout(false);
this.panelDataCollection.PerformLayout();
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.ResumeLayout(false);
this.components = new System.ComponentModel.Container();
this.btnSendFeedback = new System.Windows.Forms.Button();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.labelFeedback = new System.Windows.Forms.Label();
this.flowPanel.SuspendLayout();
this.SuspendLayout();
//
// btnSendFeedback
//
this.btnSendFeedback.AutoSize = true;
this.btnSendFeedback.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnSendFeedback.Location = new System.Drawing.Point(5, 23);
this.btnSendFeedback.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnSendFeedback.Name = "btnSendFeedback";
this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnSendFeedback.Size = new System.Drawing.Size(170, 25);
this.btnSendFeedback.TabIndex = 1;
this.btnSendFeedback.Text = "Send Feedback / Bug Report";
this.btnSendFeedback.UseVisualStyleBackColor = true;
//
// flowPanel
//
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles) ((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));
this.flowPanel.Controls.Add(this.labelFeedback);
this.flowPanel.Controls.Add(this.btnSendFeedback);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(300, 462);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
//
// labelFeedback
//
this.labelFeedback.AutoSize = true;
this.labelFeedback.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelFeedback.Location = new System.Drawing.Point(0, 0);
this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelFeedback.Name = "labelFeedback";
this.labelFeedback.Size = new System.Drawing.Size(75, 19);
this.labelFeedback.TabIndex = 0;
this.labelFeedback.Text = "FEEDBACK";
//
// TabSettingsFeedback
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.flowPanel);
this.Name = "TabSettingsFeedback";
this.Size = new System.Drawing.Size(631, 480);
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panelDataCollection;
private System.Windows.Forms.CheckBox checkDataCollection;
private System.Windows.Forms.Label labelDataCollection;
private System.Windows.Forms.Label labelFeedback;
private System.Windows.Forms.ToolTip toolTip;
private System.Windows.Forms.LinkLabel labelDataCollectionLink;
private System.Windows.Forms.Button btnSendFeedback;
private System.Windows.Forms.Button btnViewReport;
private System.Windows.Forms.Label labelDataCollectionMessage;
private System.Windows.Forms.FlowLayoutPanel flowPanel;
private System.Windows.Forms.Label labelFeedback;
#endregion
}
}

View File

@ -1,37 +1,14 @@
using System;
using System.Windows.Forms;
using TweetDuck.Management.Analytics;
using TweetDuck.Utils;
using TweetLib.Core.Features.Plugins;
namespace TweetDuck.Dialogs.Settings {
sealed partial class TabSettingsFeedback : FormSettings.BaseTab {
private readonly AnalyticsFile analyticsFile;
private readonly AnalyticsReportGenerator.ExternalInfo analyticsInfo;
private readonly PluginManager plugins;
public TabSettingsFeedback(AnalyticsManager analytics, AnalyticsReportGenerator.ExternalInfo analyticsInfo, PluginManager plugins) {
public TabSettingsFeedback() {
InitializeComponent();
this.analyticsFile = analytics?.File ?? AnalyticsFile.Load(Program.AnalyticsFilePath);
this.analyticsInfo = analyticsInfo;
this.plugins = plugins;
// feedback
checkDataCollection.Checked = Config.AllowDataCollection;
if (analytics != null) {
string collectionTime = analyticsFile.LastCollectionMessage;
labelDataCollectionMessage.Text = string.IsNullOrEmpty(collectionTime) ? "No collection yet" : "Last collection: " + collectionTime;
}
}
public override void OnReady() {
btnSendFeedback.Click += btnSendFeedback_Click;
checkDataCollection.CheckedChanged += checkDataCollection_CheckedChanged;
labelDataCollectionLink.LinkClicked += labelDataCollectionLink_LinkClicked;
btnViewReport.Click += btnViewReport_Click;
}
#region Feedback
@ -40,19 +17,6 @@ private void btnSendFeedback_Click(object sender, EventArgs e) {
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new");
}
private void checkDataCollection_CheckedChanged(object sender, EventArgs e) {
Config.AllowDataCollection = checkDataCollection.Checked;
}
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
}
private void btnViewReport_Click(object sender, EventArgs e) {
using DialogSettingsAnalytics dialog = new DialogSettingsAnalytics(AnalyticsReportGenerator.Create(analyticsFile, analyticsInfo, plugins));
dialog.ShowDialog();
}
#endregion
}
}

View File

@ -1,136 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using TweetLib.Core.Serialization;
using TweetLib.Core.Serialization.Converters;
namespace TweetDuck.Management.Analytics {
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Local")]
sealed class AnalyticsFile {
private static readonly FileSerializer<AnalyticsFile> Serializer = new FileSerializer<AnalyticsFile>();
static AnalyticsFile() {
Serializer.RegisterTypeConverter(typeof(DateTime), new SingleTypeConverter<DateTime> {
ConvertToString = value => value.ToBinary().ToString(),
ConvertToObject = value => DateTime.FromBinary(long.Parse(value))
});
Serializer.RegisterTypeConverter(typeof(Counter), new SingleTypeConverter<Counter> {
ConvertToString = value => value.Value.ToString(),
ConvertToObject = value => int.Parse(value)
});
}
public static readonly AnalyticsFile Dummy = new AnalyticsFile();
// STATE PROPERTIES
public DateTime LastDataCollection { get; set; } = DateTime.MinValue;
public string LastCollectionVersion { get; set; } = null;
public string LastCollectionMessage { get; set; } = null;
// USAGE DATA
public Counter OpenOptions { get; private set; } = 0;
public Counter OpenPlugins { get; private set; } = 0;
public Counter OpenAbout { get; private set; } = 0;
public Counter OpenGuide { get; private set; } = 0;
public Counter DesktopNotifications { get; private set; } = 0;
public Counter SoundNotifications { get; private set; } = 0;
public Counter NotificationMutes { get; private set; } = 0;
public Counter BrowserContextMenus { get; private set; } = 0;
public Counter BrowserExtraMouseButtons { get; private set; } = 0;
public Counter NotificationContextMenus { get; private set; } = 0;
public Counter NotificationExtraMouseButtons { get; private set; } = 0;
public Counter NotificationKeyboardShortcuts { get; private set; } = 0;
public Counter BrowserReloads { get; private set; } = 0;
public Counter CopiedUsernames { get; private set; } = 0;
public Counter ViewedImages { get; private set; } = 0;
public Counter DownloadedImages { get; private set; } = 0;
public Counter DownloadedVideos { get; private set; } = 0;
public Counter UsedROT13 { get; private set; } = 0;
public Counter TweetScreenshots { get; private set; } = 0;
public Counter TweetDetails { get; private set; } = 0;
public Counter VideoPlays { get; private set; } = 0;
// END OF DATA
public event EventHandler PropertyChanged;
private readonly string file;
private AnalyticsFile(string file) {
this.file = file;
}
private AnalyticsFile() {
this.file = null;
}
private void SetupProperties() {
foreach (Counter counter in GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.PropertyType == typeof(Counter)).Select(prop => (Counter) prop.GetValue(this))) {
counter.SetOwner(this);
}
}
private void OnPropertyChanged() {
PropertyChanged?.Invoke(this, EventArgs.Empty);
}
public void Save() {
if (file == null) {
return;
}
try {
Serializer.Write(file, this);
} catch (Exception e) {
Program.Reporter.HandleException("Analytics File Error", "Could not save the analytics file.", true, e);
}
}
public static AnalyticsFile Load(string file) {
AnalyticsFile config = new AnalyticsFile(file);
try {
Serializer.ReadIfExists(file, config);
} catch (Exception e) {
Program.Reporter.HandleException("Analytics File Error", "Could not open the analytics file.", true, e);
}
config.SetupProperties();
return config;
}
public interface IProvider {
AnalyticsFile AnalyticsFile { get; }
}
public sealed class Counter {
public int Value { get; private set; }
private AnalyticsFile owner;
private Counter(int value) {
this.Value = value;
}
public void SetOwner(AnalyticsFile owner) {
this.owner = owner;
}
public void Trigger() {
++Value;
owner?.OnPropertyChanged();
}
public static implicit operator int(Counter counter) => counter.Value;
public static implicit operator Counter(int value) => new Counter(value);
}
}
}

View File

@ -1,153 +0,0 @@
// Uncomment to debug reports locally
// #define ANALYTICS_LOCALHOST
// #define ANALYTICS_INSTANT
using System;
using System.Net;
using System.Threading.Tasks;
using System.Timers;
using TweetDuck.Browser;
using TweetDuck.Controls;
using TweetDuck.Utils;
using TweetLib.Core;
using TweetLib.Core.Features.Plugins;
using TweetLib.Core.Utils;
namespace TweetDuck.Management.Analytics {
sealed class AnalyticsManager : IDisposable {
private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(14);
private static readonly Uri CollectionUrl = new Uri(
#if (DEBUG && ANALYTICS_LOCALHOST)
"http://localhost/newhome/tweetduck/~breadcrumb/request.php?type=report"
#else
"https://tweetduck.chylex.com/breadcrumb/report"
#endif
);
public AnalyticsFile File { get; }
private readonly FormBrowser browser;
private readonly PluginManager plugins;
private readonly Timer currentTimer, saveTimer;
public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file) {
this.browser = browser;
this.plugins = plugins;
this.File = AnalyticsFile.Load(file);
this.File.PropertyChanged += File_PropertyChanged;
this.currentTimer = new Timer { SynchronizingObject = browser };
this.currentTimer.Elapsed += currentTimer_Elapsed;
this.saveTimer = new Timer { SynchronizingObject = browser, Interval = 60000 };
this.saveTimer.Elapsed += saveTimer_Elapsed;
if (this.File.LastCollectionVersion != Program.VersionTag) {
ScheduleReportIn(TimeSpan.FromHours(8), string.Empty);
}
else {
RestartTimer();
}
#if (DEBUG && ANALYTICS_INSTANT)
SendReport();
#endif
}
public void Dispose() {
File.PropertyChanged -= File_PropertyChanged;
if (saveTimer.Enabled) {
File.Save();
}
currentTimer.Dispose();
saveTimer.Dispose();
}
private void File_PropertyChanged(object sender, EventArgs e) {
saveTimer.Enabled = true;
}
private void saveTimer_Elapsed(object sender, ElapsedEventArgs e) {
saveTimer.Stop();
File.Save();
}
private void ScheduleReportIn(TimeSpan delay, string message = null) {
SetLastDataCollectionTime(DateTime.Now.Subtract(CollectionInterval).Add(delay), message);
}
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.LastCollectionVersion = Program.VersionTag;
File.LastCollectionMessage = message ?? dt.ToString("g", Lib.Culture);
File.Save();
RestartTimer();
}
private void RestartTimer() {
TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
int minutesTillNext = (int) (CollectionInterval.TotalMinutes - Math.Floor(diff.TotalMinutes));
currentTimer.Interval = Math.Max(minutesTillNext, 2) * 60000;
currentTimer.Start();
}
private void currentTimer_Elapsed(object sender, ElapsedEventArgs e) {
currentTimer.Stop();
TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
if (Math.Floor(diff.TotalMinutes) >= CollectionInterval.TotalMinutes) {
SendReport();
}
else {
RestartTimer();
}
}
private void SendReport() {
AnalyticsReportGenerator.ExternalInfo info = AnalyticsReportGenerator.ExternalInfo.From(browser);
Task.Factory.StartNew(() => {
AnalyticsReport report = AnalyticsReportGenerator.Create(File, info, plugins);
#if (DEBUG && !ANALYTICS_INSTANT)
System.Diagnostics.Debugger.Break();
#endif
WebUtils.NewClient(BrowserUtils.UserAgentVanilla).UploadValues(CollectionUrl, "POST", report.ToNameValueCollection());
}).ContinueWith(task => browser.InvokeAsyncSafe(() => {
if (task.Status == TaskStatus.RanToCompletion) {
SetLastDataCollectionTime(DateTime.Now);
}
else if (task.Exception != null) {
string message = null;
if (task.Exception.InnerException is WebException e) {
message = e.Status switch {
WebExceptionStatus.ConnectFailure => "Connection Error",
WebExceptionStatus.NameResolutionFailure => "DNS Error",
WebExceptionStatus.ProtocolError => "HTTP Error " + (e.Response is HttpWebResponse response ? $"{(int) response.StatusCode} ({response.StatusDescription})" : "(unknown code)"),
_ => message
};
#if DEBUG
System.IO.Stream responseStream = e.Response.GetResponseStream();
if (responseStream != null) {
System.Diagnostics.Debug.WriteLine(new System.IO.StreamReader(responseStream).ReadToEnd());
}
#endif
}
ScheduleReportIn(TimeSpan.FromHours(4), message ?? "Error: " + (task.Exception.InnerException?.Message ?? task.Exception.Message));
}
}));
}
}
}

View File

@ -1,57 +0,0 @@
using System.Collections;
using System.Collections.Specialized;
using System.Text;
namespace TweetDuck.Management.Analytics {
sealed class AnalyticsReport : IEnumerable {
private OrderedDictionary data = new OrderedDictionary(32);
private int separators;
public void Add(int ignored) { // adding separators to pretty print
data.Add((++separators).ToString(), null);
}
public void Add(string key, string value) {
data.Add(key, value);
}
public AnalyticsReport FinalizeReport() {
if (!data.IsReadOnly) {
data = data.AsReadOnly();
}
return this;
}
public IEnumerator GetEnumerator() {
return data.GetEnumerator();
}
public NameValueCollection ToNameValueCollection() {
NameValueCollection collection = new NameValueCollection();
foreach (DictionaryEntry entry in data) {
if (entry.Value != null) {
collection.Add(((string) entry.Key).ToLower().Replace(' ', '_'), (string) entry.Value);
}
}
return collection;
}
public override string ToString() {
StringBuilder build = new StringBuilder(625);
foreach (DictionaryEntry entry in data) {
if (entry.Value == null) {
build.AppendLine();
}
else {
build.AppendLine(entry.Key + ": " + entry.Value);
}
}
return build.ToString();
}
}
}

View File

@ -1,319 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Microsoft.Win32;
using TweetDuck.Browser;
using TweetDuck.Configuration;
using TweetLib.Core;
using TweetLib.Core.Features.Notifications;
using TweetLib.Core.Features.Plugins;
using TweetLib.Core.Features.Plugins.Enums;
using TweetLib.Core.Utils;
namespace TweetDuck.Management.Analytics {
static class AnalyticsReportGenerator {
public static AnalyticsReport Create(AnalyticsFile file, ExternalInfo info, PluginManager plugins) {
Dictionary<string, string> editLayoutDesign = EditLayoutDesignPluginData;
return new AnalyticsReport {
{ "App Version" , Program.VersionTag },
{ "App Type" , Program.IsPortable ? "portable" : "installed" },
{ "App Dev Tools" , Bool(UserConfig.DevToolsInContextMenu) },
0,
{ "System Name" , SystemName },
{ "System Edition" , SystemEdition },
{ "System Environment" , Environment.Is64BitOperatingSystem ? "64-bit" : "32-bit" },
{ "System Build" , SystemBuild },
{ "System Locale" , Lib.Culture.Name.ToLower() },
0,
{ "RAM" , Exact(RamSize) },
{ "GPU" , GpuVendor },
0,
{ "Screen Count" , Exact(Screen.AllScreens.Length) },
{ "Screen Resolution" , info.Resolution ?? "(unknown)" },
{ "Screen DPI" , info.DPI != null ? Exact(info.DPI.Value) : "(unknown)" },
0,
{ "Hardware Acceleration" , Bool(SysConfig.HardwareAcceleration) },
{ "Clear Cache Automatically" , Bool(SysConfig.ClearCacheAutomatically) },
{ "Clear Cache Threshold" , Exact(SysConfig.ClearCacheThreshold) },
0,
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
{ "Keep Like Follow Dialogs Open" , Bool(UserConfig.KeepLikeFollowDialogsOpen) },
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
{ "Animated Images" , Bool(UserConfig.EnableAnimatedImages) },
0,
{ "Smooth Scrolling" , Bool(UserConfig.EnableSmoothScrolling) },
{ "Custom Browser" , CustomBrowser },
{ "Zoom" , Exact(UserConfig.ZoomLevel) },
0,
{ "Spell Check" , Bool(UserConfig.EnableSpellCheck) },
{ "Spell Check Language" , UserConfig.SpellCheckLanguage.ToLower() },
{ "Translation Target Language" , UserConfig.TranslationTarget },
0,
{ "Updates" , Bool(UserConfig.EnableUpdateCheck) },
{ "Update Dismissed" , Bool(!string.IsNullOrEmpty(UserConfig.DismissedUpdate)) },
0,
{ "Tray" , TrayMode },
{ "Tray Highlight" , Bool(UserConfig.EnableTrayHighlight) },
0,
{ "Notification Position" , NotificationPosition },
{ "Notification Size" , NotificationSize },
{ "Notification Timer" , NotificationTimer },
{ "Notification Timer Speed" , RoundUp(UserConfig.NotificationDurationValue, 5) },
{ "Notification Scroll Speed" , Exact(UserConfig.NotificationScrollSpeed) },
{ "Notification Column Title" , Bool(UserConfig.DisplayNotificationColumn) },
{ "Notification Media Previews" , Bool(UserConfig.NotificationMediaPreviews) },
{ "Notification Link Skip" , Bool(UserConfig.NotificationSkipOnLinkClick) },
{ "Notification Non-Intrusive" , Bool(UserConfig.NotificationNonIntrusiveMode) },
{ "Notification Idle Pause" , Exact(UserConfig.NotificationIdlePauseSeconds) },
{ "Custom Sound Notification" , string.IsNullOrEmpty(UserConfig.NotificationSoundPath) ? "off" : Path.GetExtension(UserConfig.NotificationSoundPath) },
{ "Custom Sound Notification Volume" , RoundUp(UserConfig.NotificationSoundVolume, 5) },
0,
{ "Program Arguments" , List(ProgramArguments) },
{ "Custom CEF Arguments" , RoundUp((UserConfig.CustomCefArgs ?? string.Empty).Length, 10) },
{ "Custom Browser CSS" , RoundUp((UserConfig.CustomBrowserCSS ?? string.Empty).Length, 50) },
{ "Custom Notification CSS" , RoundUp((UserConfig.CustomNotificationCSS ?? string.Empty).Length, 50) },
0,
{ "Plugins All" , List(plugins.Plugins.Select(Plugin)) },
{ "Plugins Enabled" , List(plugins.Plugins.Where(plugins.Config.IsEnabled).Select(Plugin)) },
0,
{ "Theme" , Dict(editLayoutDesign, "_theme", "light/def") },
{ "Column Width" , Dict(editLayoutDesign, "columnWidth", "310px/def") },
{ "Font Size" , Dict(editLayoutDesign, "fontSize", "12px/def") },
{ "Large Quote Font" , Dict(editLayoutDesign, "increaseQuoteTextSize", "false/def") },
{ "Small Compose Font" , Dict(editLayoutDesign, "smallComposeTextSize", "false/def") },
{ "Avatar Radius" , Dict(editLayoutDesign, "avatarRadius", "2/def") },
{ "Hide Tweet Actions" , Dict(editLayoutDesign, "hideTweetActions", "true/def") },
{ "Move Tweet Actions" , Dict(editLayoutDesign, "moveTweetActionsToRight", "true/def") },
{ "Theme Color Tweaks" , Dict(editLayoutDesign, "themeColorTweaks", "true/def") },
{ "Revert Icons" , Dict(editLayoutDesign, "revertIcons", "true/def") },
{ "Optimize Animations" , Dict(editLayoutDesign, "optimizeAnimations", "true/def") },
{ "Reply Account Mode" , ReplyAccountConfigFromPlugin },
{ "Template Count" , Exact(TemplateCountFromPlugin) },
0,
{ "Opened Options" , LogRound(file.OpenOptions, 4) },
{ "Opened Plugins" , LogRound(file.OpenPlugins, 4) },
{ "Opened About" , LogRound(file.OpenAbout, 4) },
{ "Opened Guide" , LogRound(file.OpenGuide, 4) },
{ "Desktop Notifications" , LogRound(file.DesktopNotifications, 5) },
{ "Sound Notifications" , LogRound(file.SoundNotifications, 5) },
{ "Notification Mutes" , LogRound(file.NotificationMutes, 2) },
{ "Browser Context Menus" , LogRound(file.BrowserContextMenus, 2) },
{ "Browser Extra Mouse Buttons" , LogRound(file.BrowserExtraMouseButtons, 2) },
{ "Notification Context Menus" , LogRound(file.NotificationContextMenus, 2) },
{ "Notification Extra Mouse Buttons" , LogRound(file.NotificationExtraMouseButtons, 2) },
{ "Notification Keyboard Shortcuts" , LogRound(file.NotificationKeyboardShortcuts, 2) },
{ "Browser Reloads" , LogRound(file.BrowserReloads, 2) },
{ "Copied Usernames" , LogRound(file.CopiedUsernames, 2) },
{ "Viewed Images" , LogRound(file.ViewedImages, 2) },
{ "Downloaded Images" , LogRound(file.DownloadedImages, 2) },
{ "Downloaded Videos" , LogRound(file.DownloadedVideos, 2) },
{ "Used ROT13" , LogRound(file.UsedROT13, 2) },
{ "Tweet Screenshots" , LogRound(file.TweetScreenshots, 2) },
{ "Tweet Details" , LogRound(file.TweetDetails, 2) },
{ "Video Plays" , LogRound(file.VideoPlays, 4) }
}.FinalizeReport();
}
private static UserConfig UserConfig => Program.Config.User;
private static SystemConfig SysConfig => Program.Config.System;
private static string Bool(bool value) => value ? "on" : "off";
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 LogRound(int value, int logBase) => (value <= 0 ? 0 : (int) Math.Pow(logBase, Math.Floor(Math.Log(value, logBase)))).ToString();
private static string Plugin(Plugin plugin) => plugin.Group.GetIdentifierPrefixShort() + plugin.Identifier.Substring(plugin.Group.GetIdentifierPrefix().Length);
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 SystemName { get; }
private static string SystemEdition { get; }
private static string SystemBuild { get; }
private static int RamSize { get; }
private static string GpuVendor { get; }
private static string[] ProgramArguments { get; }
static AnalyticsReportGenerator() {
string osName, osEdition, osBuild;
try {
using RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false);
// ReSharper disable once PossibleNullReferenceException
osName = key.GetValue("ProductName") as string;
osBuild = key.GetValue("CurrentBuild") as string;
osEdition = null;
if (osName != null) {
Match match = Regex.Match(osName, @"^(.*?\d+(?:\.\d+)?) (.*)$");
if (match.Success) {
osName = match.Groups[1].Value;
osEdition = match.Groups[2].Value;
}
}
} catch {
osName = osEdition = osBuild = null;
}
SystemName = osName ?? "Windows (unknown)";
SystemEdition = osEdition ?? "(unknown)";
SystemBuild = osBuild ?? "(unknown)";
try {
using ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory");
foreach (ManagementBaseObject obj in searcher.Get()) {
RamSize += (int) ((ulong) obj["Capacity"] / (1024L * 1024L));
}
} catch {
RamSize = 0;
}
string gpu = null;
try {
using ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_VideoController");
foreach (ManagementBaseObject obj in searcher.Get()) {
string vendor = obj["Caption"] as string;
if (!string.IsNullOrEmpty(vendor)) {
gpu = vendor;
}
}
} catch {
// rip
}
GpuVendor = gpu ?? "(unknown)";
Dictionary<string, string> args = new Dictionary<string, string>();
Arguments.GetCurrentClean().ToDictionary(args);
ProgramArguments = args.Keys.Select(key => key.TrimStart('-')).ToArray();
}
private static string CustomBrowser {
get { return Path.GetFileName(UserConfig.BrowserPath) ?? string.Empty; }
}
private static string TrayMode {
get => UserConfig.TrayBehavior switch {
TrayIcon.Behavior.DisplayOnly => "icon",
TrayIcon.Behavior.MinimizeToTray => "minimize",
TrayIcon.Behavior.CloseToTray => "close",
TrayIcon.Behavior.Combined => "combined",
_ => "off"
};
}
private static string NotificationPosition {
get => UserConfig.NotificationPosition switch {
DesktopNotification.Position.TopLeft => "top left",
DesktopNotification.Position.TopRight => "top right",
DesktopNotification.Position.BottomLeft => "bottom left",
DesktopNotification.Position.BottomRight => "bottom right",
_ => "custom"
};
}
private static string NotificationSize {
get => UserConfig.NotificationSize switch {
DesktopNotification.Size.Auto => "auto",
_ => RoundUp(UserConfig.CustomNotificationSize.Width, 20) + "x" + RoundUp(UserConfig.CustomNotificationSize.Height, 20)
};
}
private static string NotificationTimer {
get {
if (!UserConfig.DisplayNotificationTimer) {
return "off";
}
else {
return UserConfig.NotificationTimerCountDown ? "count down" : "count up";
}
}
}
private static Dictionary<string, string> EditLayoutDesignPluginData {
get {
Dictionary<string, string> dict = new Dictionary<string, string>();
try {
string data = File.ReadAllText(Path.Combine(Program.PluginDataPath, "official", "edit-design", "config.json"));
foreach (Match match in Regex.Matches(data, "\"(\\w+?)\":(.*?)[,}]")) {
dict[match.Groups[1].Value] = match.Groups[2].Value.Trim('"');
}
} catch {
// rip
}
return dict;
}
}
private static int TemplateCountFromPlugin {
get {
try {
string data = File.ReadAllText(Path.Combine(Program.PluginDataPath, "official", "templates", "config.json"));
return Math.Min(StringUtils.CountOccurrences(data, "{\"name\":"), StringUtils.CountOccurrences(data, ",\"contents\":"));
} catch {
return 0;
}
}
}
private static string ReplyAccountConfigFromPlugin {
get {
try {
string data = File.ReadAllText(Path.Combine(Program.PluginDataPath, "official", "reply-account", "configuration.js")).Replace(" ", "");
Match matchType = Regex.Match(data, "defaultAccount:\"([#@])(.*?)\"(?:,|$)");
Match matchAdvanced = Regex.Match(data, "useAdvancedSelector:(.*?)(?:,|$)", RegexOptions.Multiline);
if (!matchType.Success) {
return data.Contains("defaultAccount:\"\"") ? "(legacy)" : "(unknown)";
}
string accType = matchType.Groups[1].Value == "#" ? matchType.Groups[2].Value : "account";
return matchAdvanced.Success && !matchAdvanced.Value.Contains("false") ? "advanced/" + accType : accType;
} catch {
return "(unknown)";
}
}
}
public class ExternalInfo {
public static ExternalInfo From(Form form) {
if (form == null) {
return new ExternalInfo();
}
else {
Screen screen = Screen.FromControl(form); // works on multi-monitor setups even in tray
int dpi;
using (Graphics graphics = form.CreateGraphics()) {
dpi = (int) graphics.DpiY;
}
return new ExternalInfo {
Resolution = screen.Bounds.Width + "x" + screen.Bounds.Height,
DPI = dpi
};
}
}
public string Resolution { get; private set; }
public int? DPI { get; private set; }
private ExternalInfo() {}
}
}
}

View File

@ -82,7 +82,6 @@ private void pipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e) {
case "download":
if (currentInstance != null) {
owner.AnalyticsFile.DownloadedVideos.Trigger();
TwitterUtils.DownloadVideo(currentInstance.VideoUrl, currentInstance.Username);
}

View File

@ -43,7 +43,6 @@ static class Program {
public static string UserConfigFilePath => Path.Combine(StoragePath, "TD_UserConfig.cfg");
public static string SystemConfigFilePath => Path.Combine(StoragePath, "TD_SystemConfig.cfg");
public static string PluginConfigFilePath => Path.Combine(StoragePath, "TD_PluginConfig.cfg");
public static string AnalyticsFilePath => Path.Combine(StoragePath, "TD_Analytics.cfg");
private static string ErrorLogFilePath => Path.Combine(StoragePath, "TD_Log.txt");
private static string ConsoleLogFilePath => Path.Combine(StoragePath, "TD_Console.txt");

View File

@ -13,11 +13,6 @@
<p>Click <strong>Show Guide</strong> to see awesome features TweetDuck offers, or view the guide later by going to <strong>About TweetDuck</strong> and clicking the help button on top.</p>
</div>
<footer class="txt-right">
<div class="anondata">
<input id="td-anonymous-data" type="checkbox" checked>
<label for="td-anonymous-data">Send anonymous usage data</label>
<label>&nbsp;(<a href="https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data" rel="nofollow">learn more</a>)</label>
</div>
<button class="Button--primary" data-guide><span class="label">Show Guide</span></button>
<button class="Button--secondary"><span class="label">Close</span></button>
</footer>

View File

@ -63,18 +63,3 @@
#td-introduction-modal button {
margin-left: 8px;
}
#td-introduction-modal .anondata {
float: left;
margin: 5px 7px;
}
#td-introduction-modal .anondata input {
vertical-align: -10%;
}
#td-introduction-modal .anondata label {
cursor: pointer;
display: inline-block;
font-size: 14px;
}

View File

@ -30,10 +30,9 @@
ele.find("button, a.mdl-dismiss").click(function(){
const showGuide = $(this)[0].hasAttribute("data-guide");
const allowDataCollection = $("#td-anonymous-data").is(":checked");
ele.fadeOut(200, function(){
$TD.onIntroductionClosed(showGuide, allowDataCollection);
$TD.onIntroductionClosed(showGuide);
ele.remove();
css.remove();
});

View File

@ -102,10 +102,6 @@
<Compile Include="Configuration\SystemConfig.cs" />
<Compile Include="Configuration\UserConfig.cs" />
<Compile Include="Controls\ControlExtensions.cs" />
<Compile Include="Management\Analytics\AnalyticsFile.cs" />
<Compile Include="Management\Analytics\AnalyticsManager.cs" />
<Compile Include="Management\Analytics\AnalyticsReport.cs" />
<Compile Include="Management\Analytics\AnalyticsReportGenerator.cs" />
<Compile Include="Management\BrowserCache.cs" />
<Compile Include="Management\ClipboardManager.cs" />
<Compile Include="Management\FormManager.cs" />
@ -190,12 +186,6 @@
<Compile Include="Dialogs\FormPlugins.Designer.cs">
<DependentUpon>FormPlugins.cs</DependentUpon>
</Compile>
<Compile Include="Dialogs\Settings\DialogSettingsAnalytics.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Dialogs\Settings\DialogSettingsAnalytics.Designer.cs">
<DependentUpon>DialogSettingsAnalytics.cs</DependentUpon>
</Compile>
<Compile Include="Dialogs\Settings\DialogSettingsExternalProgram.cs">
<SubType>Form</SubType>
</Compile>

View File

@ -28,13 +28,5 @@ public static string GetIdentifierPrefix(this PluginGroup group) {
_ => "unknown/"
};
}
public static string GetIdentifierPrefixShort(this PluginGroup group) {
return group switch {
PluginGroup.Official => "o/",
PluginGroup.Custom => "c/",
_ => "?/"
};
}
}
}