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

Refactor code to avoid nulls ()

* Ensure potential nulls have a fallback value & add/remove null checks

* Refactor update check code to avoid nulls

* Refactor ProfileManager exception handling to avoid nulls

* Refactor a few more various classes and fix nulls in ContextInfo

* Force c#7 everywhere and revert usage of newer features from cherry-picked commits

* Remove unused #pragma declaration
This commit is contained in:
Daniel Chýlek 2018-03-07 14:37:03 +01:00 committed by GitHub
parent ed317a4e46
commit f1f90a2ee3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 102 additions and 81 deletions

View File

@ -132,7 +132,7 @@ void ViewImage(string path){
}
string url = LastLink.GetMediaSource(parameters);
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url));
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url) ?? Path.GetRandomFileName());
if (File.Exists(file)){
ViewImage(file);
@ -187,7 +187,7 @@ protected void OpenBrowser(Control control, string url){
}
protected void SetClipboardText(Control control, string text){
control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text ?? string.Empty, TextDataFormat.UnicodeText));
}
protected static void AddDebugMenuItems(IMenuModel model){

View File

@ -11,7 +11,12 @@ public ContextInfo(){
}
public void SetLink(string type, string url){
Link = new LinkInfo(string.IsNullOrEmpty(url) ? null : type, url);
if (string.IsNullOrEmpty(url)){
Link = new LinkInfo();
}
else{
Link = new LinkInfo(type, url);
}
}
public void SetChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){

View File

@ -23,7 +23,6 @@ public enum Items{
}
public bool IsRestarting { get; private set; }
public Exception LastException { get; private set; }
private readonly string file;
private readonly PluginManager plugins;
@ -67,7 +66,7 @@ public bool Export(Items items){
return true;
}catch(Exception e){
LastException = e;
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting TweetDuck profile.", true, e);
return false;
}
}
@ -100,8 +99,7 @@ public Items FindImportItems(){
}
}
}
}catch(Exception e){
LastException = e;
}catch(Exception){
items = Items.None;
}
@ -164,12 +162,12 @@ public bool Import(Items items){
}
if (missingPlugins.Count > 0){
FormMessage.Information("Importing TweetDuck Profile", "Detected missing plugins when importing plugin data:\n"+string.Join("\n", missingPlugins), FormMessage.OK);
FormMessage.Information("Profile Import", "Detected missing plugins when importing plugin data:\n"+string.Join("\n", missingPlugins), FormMessage.OK);
}
return true;
}catch(Exception e){
LastException = e;
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing TweetDuck profile.", true, e);
return false;
}
}
@ -199,15 +197,23 @@ public static void DeleteCookies(){
}
private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){
return Directory.Exists(root) ? Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo{
Full = fullPath,
Relative = fullPath.Substring(root.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) // strip leading separator character
}) : Enumerable.Empty<PathInfo>();
if (Directory.Exists(root)){
int rootLength = root.Length;
return Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo(fullPath, rootLength));
}
else{
return Enumerable.Empty<PathInfo>();
}
}
private sealed class PathInfo{
public string Full { get; set; }
public string Relative { get; set; }
public string Full { get; }
public string Relative { get; }
public PathInfo(string fullPath, int rootLength){
this.Full = fullPath;
this.Relative = fullPath.Substring(rootLength).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); // strip leading separator character
}
}
}

View File

@ -14,8 +14,6 @@ sealed class VideoPlayer : IDisposable{
public event EventHandler ProcessExited;
private readonly FormBrowser owner;
private string lastUrl;
private string lastUsername;
private Instance currentInstance;
private bool isClosing;
@ -30,9 +28,6 @@ public void Launch(string url, string username){
Destroy();
isClosing = false;
}
lastUrl = url;
lastUsername = username;
try{
DuplexPipe.Server pipe = DuplexPipe.CreateServer();
@ -46,7 +41,7 @@ public void Launch(string url, string username){
UseShellExecute = false,
RedirectStandardOutput = true
})) != null){
currentInstance = new Instance(process, pipe);
currentInstance = new Instance(process, pipe, url, username);
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
@ -81,9 +76,9 @@ private void pipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e){
break;
case "download":
if (!string.IsNullOrEmpty(lastUrl)){
if (currentInstance != null){
owner.AnalyticsFile.DownloadedVideos.Trigger();
TwitterUtils.DownloadVideo(lastUrl, lastUsername);
TwitterUtils.DownloadVideo(currentInstance.Url, currentInstance.Username);
}
break;
@ -147,6 +142,7 @@ private void process_Exited(object sender, EventArgs e){
}
int exitCode = currentInstance.Process.ExitCode;
string url = currentInstance.Url;
currentInstance.Dispose();
currentInstance = null;
@ -154,14 +150,14 @@ private void process_Exited(object sender, EventArgs e){
switch(exitCode){
case 3: // CODE_LAUNCH_FAIL
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(lastUrl);
BrowserUtils.OpenExternalBrowser(url);
}
break;
case 4: // CODE_MEDIA_ERROR
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(lastUrl);
BrowserUtils.OpenExternalBrowser(url);
}
break;
@ -185,9 +181,14 @@ public bool Running{
public Process Process { get; }
public DuplexPipe.Server Pipe { get; }
public Instance(Process process, DuplexPipe.Server pipe){
public string Url { get; }
public string Username { get; }
public Instance(Process process, DuplexPipe.Server pipe, string url, string username){
this.Process = process;
this.Pipe = pipe;
this.Url = url;
this.Username = username;
}
public void KillAndDispose(){

View File

@ -24,7 +24,7 @@ protected override FormBorderStyle NotificationBorderStyle{
private readonly TweetNotification exampleNotification;
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
string exampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true).Replace("{avatar}", TweetNotification.AppLogo.Url);
string exampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true)?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
#if DEBUG
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");

View File

@ -217,7 +217,9 @@ protected virtual void UpdateTitle(){
}
public void ShowTweetDetail(){
owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl);
if (currentNotification != null){
owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl);
}
}
public void MoveToVisibleLocation(){

View File

@ -8,7 +8,7 @@
namespace TweetDuck.Core.Notification{
sealed class TweetNotification{
private const string DefaultHeadLayout = @"<html id='tduck' class='os-windows txt-size--14' data-td-font='medium' data-td-theme='dark'><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>";
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css");
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css") ?? string.Empty;
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
public static TweetNotification Example(string html, int characters){

View File

@ -21,7 +21,7 @@ static AnalyticsFile(){
});
}
public static readonly AnalyticsFile Dummy = new AnalyticsFile(null);
public static readonly AnalyticsFile Dummy = new AnalyticsFile();
// STATE PROPERTIES
@ -67,6 +67,10 @@ 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);

View File

@ -58,11 +58,8 @@ private FormGuide(string url, FormBrowser owner){
InitializeComponent();
Text = Program.BrandName+" Guide";
if (owner != null){
Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4);
VisibleChanged += (sender, args) => this.MoveToCenter(owner);
}
Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4);
VisibleChanged += (sender, args) => this.MoveToCenter(owner);
this.browser = new ChromiumWebBrowser(url){
MenuHandler = new ContextMenuGuide(owner),

View File

@ -164,9 +164,6 @@ private void btnContinue_Click(object sender, EventArgs e){
ShouldReloadBrowser = true;
}
}
else{
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing TweetDuck profile.", true, importManager.LastException);
}
DialogResult = DialogResult.OK;
Close();
@ -191,12 +188,8 @@ private void btnContinue_Click(object sender, EventArgs e){
Program.UserConfig.Save();
Program.SystemConfig.Save();
ProfileManager manager = new ProfileManager(file, plugins);
if (!manager.Export(SelectedItems)){
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting TweetDuck profile.", true, manager.LastException);
}
new ProfileManager(file, plugins).Export(SelectedItems);
DialogResult = DialogResult.OK;
Close();

View File

@ -170,7 +170,7 @@ private void btnCheckUpdates_Click(object sender, EventArgs e){
}
}
private void updates_CheckFinished(object sender, UpdateEventArgs e){
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
this.InvokeAsyncSafe(() => {
if (e.EventId == updateCheckEventId){
btnCheckUpdates.Enabled = true;

View File

@ -42,12 +42,12 @@ private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){
}
private void comboBoxSpellCheckLanguage_SelectedValueChanged(object sender, EventArgs e){
Config.SpellCheckLanguage = (comboBoxSpellCheckLanguage.SelectedItem as LocaleUtils.Item)?.Code;
Config.SpellCheckLanguage = (comboBoxSpellCheckLanguage.SelectedItem as LocaleUtils.Item)?.Code ?? "en-US";
PromptRestart();
}
private void comboBoxTranslationTarget_SelectedValueChanged(object sender, EventArgs e){
Config.TranslationTarget = (comboBoxTranslationTarget.SelectedItem as LocaleUtils.Item)?.Code;
Config.TranslationTarget = (comboBoxTranslationTarget.SelectedItem as LocaleUtils.Item)?.Code ?? "en";
}
}
}

View File

@ -211,7 +211,7 @@ public void UpdateProperties(){
}
public void InjectBrowserCSS(){
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css").TrimEnd());
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css")?.TrimEnd() ?? string.Empty);
}
public void ReinjectCustomCSS(string css){

View File

@ -36,7 +36,7 @@ public PluginControl(PluginManager pluginManager, Plugin plugin) : this(){
labelDescription.Visible = false;
}
panelDescription_Resize(panelDescription, null);
panelDescription_Resize(panelDescription, EventArgs.Empty);
}
private void panelDescription_Resize(object sender, EventArgs e){

View File

@ -151,10 +151,9 @@ private static void Main(){
Application.ApplicationExit += (sender, args) => ExitCleanup();
UpdaterSettings updaterSettings = new UpdaterSettings{
UpdaterSettings updaterSettings = new UpdaterSettings(InstallerPath){
AllowPreReleases = Arguments.HasFlag(Arguments.ArgDebugUpdates),
DismissedUpdate = UserConfig.DismissedUpdate,
InstallerDownloadFolder = InstallerPath
DismissedUpdate = UserConfig.DismissedUpdate
};
FormBrowser mainForm = new FormBrowser(updaterSettings);

View File

@ -291,6 +291,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Reporter.cs" />
<Compile Include="Updates\Events\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
@ -312,7 +313,7 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\ScriptLoader.cs" />
<Compile Include="Updates\UpdateEventArgs.cs" />
<Compile Include="Updates\Events\UpdateEventArgs.cs" />
<Compile Include="Updates\UpdaterSettings.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,13 @@
using System;
namespace TweetDuck.Updates{
sealed class UpdateCheckEventArgs : EventArgs{
public int EventId { get; }
public bool IsUpdateAvailable { get; }
public UpdateCheckEventArgs(int eventId, bool isUpdateAvailable){
this.EventId = eventId;
this.IsUpdateAvailable = isUpdateAvailable;
}
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace TweetDuck.Updates{
sealed class UpdateEventArgs : EventArgs{
public UpdateInfo UpdateInfo { get; }
public UpdateEventArgs(UpdateInfo updateInfo){
this.UpdateInfo = updateInfo;
}
}
}

View File

@ -1,20 +0,0 @@
using System;
namespace TweetDuck.Updates{
sealed class UpdateEventArgs : EventArgs{
public int EventId { get; }
public UpdateInfo UpdateInfo { get; }
public bool IsUpdateAvailable => UpdateInfo != null;
public UpdateEventArgs(int eventId, UpdateInfo updateInfo){
this.EventId = eventId;
this.UpdateInfo = updateInfo;
}
public UpdateEventArgs(UpdateInfo updateInfo){
this.EventId = updateInfo.EventId;
this.UpdateInfo = updateInfo;
}
}
}

View File

@ -16,7 +16,7 @@ sealed class UpdateHandler{
public event EventHandler<UpdateEventArgs> UpdateAccepted;
public event EventHandler<UpdateEventArgs> UpdateDismissed;
public event EventHandler<UpdateEventArgs> CheckFinished;
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
private ushort lastEventId;
private UpdateInfo lastUpdateInfo;
@ -93,7 +93,7 @@ private void TriggerUpdateDismissedEvent(UpdateEventArgs args){
UpdateDismissed?.Invoke(this, args);
}
private void TriggerCheckFinishedEvent(UpdateEventArgs args){
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
CheckFinished?.Invoke(this, args);
}
@ -114,8 +114,8 @@ public void OnUpdateCheckFinished(int eventId, string versionTag, string downloa
owner.lastUpdateInfo = new UpdateInfo(owner.settings, eventId, versionTag, downloadUrl);
owner.lastUpdateInfo.BeginSilentDownload();
}
owner.TriggerCheckFinishedEvent(new UpdateEventArgs(eventId, owner.lastUpdateInfo));
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, owner.lastUpdateInfo != null));
}
public void OnUpdateAccepted(){

View File

@ -1,7 +1,12 @@
namespace TweetDuck.Updates{
sealed class UpdaterSettings{
public string InstallerDownloadFolder { get; }
public bool AllowPreReleases { get; set; }
public string DismissedUpdate { get; set; }
public string InstallerDownloadFolder { get; set; }
public UpdaterSettings(string installerDownloadFolder){
this.InstallerDownloadFolder = installerDownloadFolder;
}
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -20,6 +20,7 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>7</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>

View File

@ -15,6 +15,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
<LangVersion>7</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -22,6 +22,7 @@
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -22,6 +22,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
<LangVersion>7</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>