Fixes for the UpdateService and AboutForm, they were using the wrong version.

This commit is contained in:
Robin 2018-12-13 13:39:52 +01:00
commit f1c8a34a93
3 changed files with 444 additions and 440 deletions

View file

@ -24,6 +24,7 @@
#region Usings #region Usings
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.ServiceModel.Syndication; using System.ServiceModel.Syndication;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -42,39 +43,39 @@ using Greenshot.Ui.Notifications.ViewModels;
namespace Greenshot.Components namespace Greenshot.Components
{ {
/// <summary> /// <summary>
/// This processes the information, if there are updates available. /// This processes the information, if there are updates available.
/// </summary> /// </summary>
[Service(nameof(UpdateService), nameof(MainFormStartup))] [Service(nameof(UpdateService), nameof(MainFormStartup))]
public class UpdateService : IStartup, IShutdown, IVersionProvider public class UpdateService : IStartup, IShutdown, IVersionProvider
{ {
private static readonly LogSource Log = new LogSource(); private static readonly LogSource Log = new LogSource();
private static readonly Regex VersionRegex = new Regex(@"^.*[^-]-(?<version>[0-9\.]+)\-(?<type>(release|beta|rc[0-9]+))\.exe.*", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex VersionRegex = new Regex(@"^.*[^-]-(?<version>[0-9\.]+)\-(?<type>(release|beta|rc[0-9]+))\.exe.*", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Uri UpdateFeed = new Uri("http://getgreenshot.org/project-feed/"); private static readonly Uri UpdateFeed = new Uri("http://getgreenshot.org/project-feed/");
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly ICoreConfiguration _coreConfiguration; private readonly ICoreConfiguration _coreConfiguration;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly Func<Version, Owned<UpdateNotificationViewModel>> _updateNotificationViewModelFactory; private readonly Func<Version, Owned<UpdateNotificationViewModel>> _updateNotificationViewModelFactory;
/// <inheritdoc /> /// <inheritdoc />
public Version CurrentVersion { get; } public Version CurrentVersion { get; }
/// <inheritdoc /> /// <inheritdoc />
public Version LatestVersion { get; private set; } public Version LatestVersion { get; private set; }
/// <summary> /// <summary>
/// The latest beta version /// The latest beta version
/// </summary> /// </summary>
public Version BetaVersion { get; private set; } public Version BetaVersion { get; private set; }
/// <summary> /// <summary>
/// The latest RC version /// The latest RC version
/// </summary> /// </summary>
public Version ReleaseCandidateVersion { get; private set; } public Version ReleaseCandidateVersion { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
public bool IsUpdateAvailable => LatestVersion > CurrentVersion; public bool IsUpdateAvailable => LatestVersion > CurrentVersion;
/// <summary> /// <summary>
/// Constructor with dependencies /// Constructor with dependencies
@ -86,26 +87,27 @@ namespace Greenshot.Components
ICoreConfiguration coreConfiguration, ICoreConfiguration coreConfiguration,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
Func<Version, Owned<UpdateNotificationViewModel>> updateNotificationViewModelFactory) Func<Version, Owned<UpdateNotificationViewModel>> updateNotificationViewModelFactory)
{ {
_coreConfiguration = coreConfiguration; _coreConfiguration = coreConfiguration;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_updateNotificationViewModelFactory = updateNotificationViewModelFactory; _updateNotificationViewModelFactory = updateNotificationViewModelFactory;
LatestVersion = CurrentVersion = GetType().Assembly.GetName().Version; var version = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location);
_coreConfiguration.LastSaveWithVersion = CurrentVersion.ToString(); LatestVersion = CurrentVersion = new Version(version.FileMajorPart, version.FileMinorPart, version.FileBuildPart);
} _coreConfiguration.LastSaveWithVersion = CurrentVersion.ToString();
}
/// <inheritdoc /> /// <inheritdoc />
public void Startup() public void Startup()
{ {
var ignore = BackgroundTask(() => TimeSpan.FromDays(_coreConfiguration.UpdateCheckInterval), UpdateCheck, _cancellationTokenSource.Token); var ignore = BackgroundTask(() => TimeSpan.FromDays(_coreConfiguration.UpdateCheckInterval), UpdateCheck, _cancellationTokenSource.Token);
} }
/// <inheritdoc /> /// <inheritdoc />
public void Shutdown() public void Shutdown()
{ {
if (!_cancellationTokenSource.IsCancellationRequested) if (!_cancellationTokenSource.IsCancellationRequested)
{ {
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
} }
} }
@ -116,48 +118,48 @@ namespace Greenshot.Components
/// <param name="reoccurringTask">Func which returns a task</param> /// <param name="reoccurringTask">Func which returns a task</param>
/// <param name="cancellationToken">CancellationToken</param> /// <param name="cancellationToken">CancellationToken</param>
/// <returns>Task</returns> /// <returns>Task</returns>
private async Task BackgroundTask(Func<TimeSpan> intervalFactory, Func<CancellationToken, Task> reoccurringTask, CancellationToken cancellationToken = default) private async Task BackgroundTask(Func<TimeSpan> intervalFactory, Func<CancellationToken, Task> reoccurringTask, CancellationToken cancellationToken = default)
{ {
// Initial delay, to make sure this doesn't happen at the startup // Initial delay, to make sure this doesn't happen at the startup
await Task.Delay(20000, cancellationToken); await Task.Delay(20000, cancellationToken);
Log.Info().WriteLine("Starting background task to check for updates"); Log.Info().WriteLine("Starting background task to check for updates");
await Task.Run(async () => await Task.Run(async () =>
{ {
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
var interval = intervalFactory(); var interval = intervalFactory();
var task = reoccurringTask; var task = reoccurringTask;
// If the check is disabled, handle that here // If the check is disabled, handle that here
if (TimeSpan.Zero == interval) if (TimeSpan.Zero == interval)
{ {
interval = TimeSpan.FromMinutes(10); interval = TimeSpan.FromMinutes(10);
task = c => Task.FromResult(true); task = c => Task.FromResult(true);
} }
try try
{ {
await task(cancellationToken).ConfigureAwait(false); await task(cancellationToken).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error().WriteLine(ex, "Error occured when trying to check for updates."); Log.Error().WriteLine(ex, "Error occured when trying to check for updates.");
} }
try try
{ {
await Task.Delay(interval, cancellationToken).ConfigureAwait(false); await Task.Delay(interval, cancellationToken).ConfigureAwait(false);
} }
catch (TaskCanceledException) catch (TaskCanceledException)
{ {
// Ignore, this always happens // Ignore, this always happens
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error().WriteLine(ex, "Error occured await for the next update check."); Log.Error().WriteLine(ex, "Error occured await for the next update check.");
} }
} }
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -165,50 +167,50 @@ namespace Greenshot.Components
/// </summary> /// </summary>
/// <param name="cancellationToken">CancellationToken</param> /// <param name="cancellationToken">CancellationToken</param>
/// <returns>Task</returns> /// <returns>Task</returns>
private async Task UpdateCheck(CancellationToken cancellationToken = default) private async Task UpdateCheck(CancellationToken cancellationToken = default)
{ {
Log.Info().WriteLine("Checking for updates from {0}", UpdateFeed); Log.Info().WriteLine("Checking for updates from {0}", UpdateFeed);
var updateFeed = await UpdateFeed.GetAsAsync<SyndicationFeed>(cancellationToken); var updateFeed = await UpdateFeed.GetAsAsync<SyndicationFeed>(cancellationToken);
if (updateFeed == null) if (updateFeed == null)
{ {
return; return;
} }
_coreConfiguration.LastUpdateCheck = DateTime.Now; _coreConfiguration.LastUpdateCheck = DateTime.Now;
ProcessFeed(updateFeed); ProcessFeed(updateFeed);
if (IsUpdateAvailable) if (IsUpdateAvailable)
{ {
ShowUpdate(LatestVersion); ShowUpdate(LatestVersion);
} }
} }
/// <summary> /// <summary>
/// This takes care of creating the toast view model, publishing it, and disposing afterwards /// This takes care of creating the toast view model, publishing it, and disposing afterwards
/// </summary> /// </summary>
private void ShowUpdate(Version latestVersion) private void ShowUpdate(Version latestVersion)
{ {
// Create the ViewModel "part" // Create the ViewModel "part"
var message = _updateNotificationViewModelFactory(latestVersion); var message = _updateNotificationViewModelFactory(latestVersion);
// Prepare to dispose the view model parts automatically if it's finished // Prepare to dispose the view model parts automatically if it's finished
void DisposeHandler(object sender, DeactivationEventArgs args) void DisposeHandler(object sender, DeactivationEventArgs args)
{ {
message.Value.Deactivated -= DisposeHandler; message.Value.Deactivated -= DisposeHandler;
message.Dispose(); message.Dispose();
} }
message.Value.Deactivated += DisposeHandler; message.Value.Deactivated += DisposeHandler;
// Show the ViewModel as toast // Show the ViewModel as toast
_eventAggregator.PublishOnUIThread(message.Value); _eventAggregator.PublishOnUIThread(message.Value);
} }
/// <summary> /// <summary>
/// Process the update feed to get the latest version /// Process the update feed to get the latest version
/// </summary> /// </summary>
/// <param name="updateFeed"></param> /// <param name="updateFeed"></param>
public void ProcessFeed(SyndicationFeed updateFeed) public void ProcessFeed(SyndicationFeed updateFeed)
{ {
var versions = var versions =
from link in updateFeed.Items.SelectMany(i => i.Links) from link in updateFeed.Items.SelectMany(i => i.Links)
@ -217,28 +219,28 @@ namespace Greenshot.Components
group match by Regex.Replace(match.Groups["type"].Value, @"[\d-]", string.Empty) into groupedVersions group match by Regex.Replace(match.Groups["type"].Value, @"[\d-]", string.Empty) into groupedVersions
select groupedVersions.OrderByDescending(m => new Version(m.Groups["version"].Value)).First(); select groupedVersions.OrderByDescending(m => new Version(m.Groups["version"].Value)).First();
foreach (var versionMatch in versions) foreach (var versionMatch in versions)
{ {
var version = new Version(versionMatch.Groups["version"].Value); var version = new Version(versionMatch.Groups["version"].Value);
var type = versionMatch.Groups["type"].Value; var type = versionMatch.Groups["type"].Value;
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{
continue;
}
Log.Debug().WriteLine("Got {0} {1}", type, version);
if ("release".Equals(type, StringComparison.OrdinalIgnoreCase))
{
LatestVersion = version;
}
if ("beta".Equals(type, StringComparison.OrdinalIgnoreCase))
{
BetaVersion = version;
}
if ("rc".Equals(type, StringComparison.OrdinalIgnoreCase))
{ {
ReleaseCandidateVersion = version; continue;
} }
Log.Debug().WriteLine("Got {0} {1}", type, version);
if ("release".Equals(type, StringComparison.OrdinalIgnoreCase))
{
LatestVersion = version;
}
if ("beta".Equals(type, StringComparison.OrdinalIgnoreCase))
{
BetaVersion = version;
}
if ("rc".Equals(type, StringComparison.OrdinalIgnoreCase))
{
ReleaseCandidateVersion = version;
}
} }
} }
} }
} }

View file

@ -117,7 +117,7 @@ namespace Greenshot.Forms {
this.linkLblBugs.Size = new System.Drawing.Size(465, 23); this.linkLblBugs.Size = new System.Drawing.Size(465, 23);
this.linkLblBugs.TabIndex = 8; this.linkLblBugs.TabIndex = 8;
this.linkLblBugs.TabStop = true; this.linkLblBugs.TabStop = true;
this.linkLblBugs.Text = "http://getgreenshot.org/tickets/?version=" + Assembly.GetEntryAssembly().GetName().Version; this.linkLblBugs.Text = "http://getgreenshot.org/tickets/?version=" + _versionProvider.CurrentVersion;
this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked);
// //
// lblBugs // lblBugs
@ -135,7 +135,7 @@ namespace Greenshot.Forms {
this.linkLblDonations.Size = new System.Drawing.Size(465, 23); this.linkLblDonations.Size = new System.Drawing.Size(465, 23);
this.linkLblDonations.TabIndex = 10; this.linkLblDonations.TabIndex = 10;
this.linkLblDonations.TabStop = true; this.linkLblDonations.TabStop = true;
this.linkLblDonations.Text = "http://getgreenshot.org/support/?version=" + Assembly.GetEntryAssembly().GetName().Version; this.linkLblDonations.Text = "http://getgreenshot.org/support/?version=" + _versionProvider.CurrentVersion;
this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked);
// //
// lblDonations // lblDonations

View file

@ -45,371 +45,373 @@ using Greenshot.Gfx;
namespace Greenshot.Forms namespace Greenshot.Forms
{ {
/// <summary> /// <summary>
/// The about form /// The about form
/// </summary> /// </summary>
public sealed partial class AboutForm : AnimatingForm public sealed partial class AboutForm : AnimatingForm
{ {
private readonly IGreenshotLanguage _greenshotlanguage; private readonly IGreenshotLanguage _greenshotlanguage;
private readonly IVersionProvider _versionProvider;
private static readonly LogSource Log = new LogSource(); private static readonly LogSource Log = new LogSource();
// Variables are used to define the location of the dots // Variables are used to define the location of the dots
private const int w = 13; private const int w = 13;
private const int p1 = 7; private const int p1 = 7;
private const int p2 = p1 + w; private const int p2 = p1 + w;
private const int p3 = p2 + w; private const int p3 = p2 + w;
private const int p4 = p3 + w; private const int p4 = p3 + w;
private const int p5 = p4 + w; private const int p5 = p4 + w;
private const int p6 = p5 + w; private const int p6 = p5 + w;
private const int p7 = p6 + w; private const int p7 = p6 + w;
private readonly Color _backColor = Color.FromArgb(61, 61, 61); private readonly Color _backColor = Color.FromArgb(61, 61, 61);
private readonly ColorAnimator _backgroundAnimation; private readonly ColorAnimator _backgroundAnimation;
private readonly IList<Color> _colorFlow = new List<Color>(); private readonly IList<Color> _colorFlow = new List<Color>();
private readonly IDisposable _dpiSubscription; private readonly IDisposable _dpiSubscription;
// 0 1 2 3 4 // 0 1 2 3 4
// 5 6 // 5 6
// 7 8 // 7 8
// 9 10 11 12 13 // 9 10 11 12 13
// 14 15 16 17 // 14 15 16 17
// 18 19 20 21 22 23 // 18 19 20 21 22 23
// The order in which we draw the dots & flow the collors. // The order in which we draw the dots & flow the collors.
private readonly IList<int> _flowOrder = new List<int> {4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11}; private readonly IList<int> _flowOrder = new List<int> {4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11};
/// <summary> /// <summary>
/// The location of every dot in the "G" /// The location of every dot in the "G"
/// </summary> /// </summary>
private readonly IList<Point> _gSpots = new List<Point> private readonly IList<Point> _gSpots = new List<Point>
{ {
// Top row // Top row
new Point(p2, p1), // 0 new Point(p2, p1), // 0
new Point(p3, p1), // 1 new Point(p3, p1), // 1
new Point(p4, p1), // 2 new Point(p4, p1), // 2
new Point(p5, p1), // 3 new Point(p5, p1), // 3
new Point(p6, p1), // 4 new Point(p6, p1), // 4
// Second row // Second row
new Point(p1, p2), // 5 new Point(p1, p2), // 5
new Point(p2, p2), // 6 new Point(p2, p2), // 6
// Third row // Third row
new Point(p1, p3), // 7 new Point(p1, p3), // 7
new Point(p2, p3), // 8 new Point(p2, p3), // 8
// Fourth row // Fourth row
new Point(p1, p4), // 9 new Point(p1, p4), // 9
new Point(p2, p4), // 10 new Point(p2, p4), // 10
new Point(p5, p4), // 11 new Point(p5, p4), // 11
new Point(p6, p4), // 12 new Point(p6, p4), // 12
new Point(p7, p4), // 13 new Point(p7, p4), // 13
// Fifth row // Fifth row
new Point(p1, p5), // 14 new Point(p1, p5), // 14
new Point(p2, p5), // 15 new Point(p2, p5), // 15
new Point(p6, p5), // 16 new Point(p6, p5), // 16
new Point(p7, p5), // 17 new Point(p7, p5), // 17
// Sixth row // Sixth row
new Point(p1, p6), // 18 new Point(p1, p6), // 18
new Point(p2, p6), // 19 new Point(p2, p6), // 19
new Point(p3, p6), // 20 new Point(p3, p6), // 20
new Point(p4, p6), // 21 new Point(p4, p6), // 21
new Point(p5, p6), // 22 new Point(p5, p6), // 22
new Point(p6, p6) // 23 new Point(p6, p6) // 23
}; };
private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); private readonly Color _pixelColor = Color.FromArgb(138, 255, 0);
private readonly IList<Color> _pixelColors = new List<Color>(); private readonly IList<Color> _pixelColors = new List<Color>();
private readonly IList<RectangleAnimator> _pixels = new List<RectangleAnimator>(); private readonly IList<RectangleAnimator> _pixels = new List<RectangleAnimator>();
private readonly Random _rand = new Random(); private readonly Random _rand = new Random();
private Bitmap _bitmap; private Bitmap _bitmap;
private int _colorIndex; private int _colorIndex;
private bool _hasAnimationsLeft; private bool _hasAnimationsLeft;
private int _scrollCount; private int _scrollCount;
// Variables used for the color-cycle // Variables used for the color-cycle
private int _waitFrames; private int _waitFrames;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public AboutForm( public AboutForm(
ICoreConfiguration coreConfiguration, ICoreConfiguration coreConfiguration,
IGreenshotLanguage greenshotlanguage, IGreenshotLanguage greenshotlanguage,
IVersionProvider versionProvider IVersionProvider versionProvider
) : base(coreConfiguration, greenshotlanguage) ) : base(coreConfiguration, greenshotlanguage)
{ {
_greenshotlanguage = greenshotlanguage; _greenshotlanguage = greenshotlanguage;
// Make sure our resources are removed again. _versionProvider = versionProvider;
Disposed += Cleanup; // Make sure our resources are removed again.
FormClosing += Cleanup; Disposed += Cleanup;
FormClosing += Cleanup;
// Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded.
EnableAnimation = true; EnableAnimation = true;
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //
InitializeComponent(); InitializeComponent();
// Use the self drawn image, first we create the background to be the backcolor (as we animate from this) // Use the self drawn image, first we create the background to be the backcolor (as we animate from this)
_bitmap = BitmapFactory.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor); _bitmap = BitmapFactory.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor);
pictureBox1.Image = _bitmap; pictureBox1.Image = _bitmap;
_dpiSubscription = FormDpiHandler.OnDpiChanged.Subscribe(info => _dpiSubscription = FormDpiHandler.OnDpiChanged.Subscribe(info =>
{ {
pictureBox1.Size = FormDpiHandler.ScaleWithCurrentDpi(new NativeSize(90,90)); pictureBox1.Size = FormDpiHandler.ScaleWithCurrentDpi(new NativeSize(90,90));
}); });
var versionInfo = $@"Greenshot {versionProvider.CurrentVersion} {(coreConfiguration.IsPortable ? " Portable" : "")} ({OsInfo.Bits} bit)"; var versionInfo = $@"Greenshot {versionProvider.CurrentVersion} {(coreConfiguration.IsPortable ? " Portable" : "")} ({OsInfo.Bits} bit)";
if (versionProvider.IsUpdateAvailable) if (versionProvider.IsUpdateAvailable)
{ {
versionInfo += $" latest is: {versionProvider.LatestVersion}"; versionInfo += $" latest is: {versionProvider.LatestVersion}";
} }
lblTitle.Text = versionInfo; lblTitle.Text = versionInfo;
// Number of frames the pixel animation takes // Number of frames the pixel animation takes
var frames = FramesForMillis(2000); var frames = FramesForMillis(2000);
// The number of frames the color-cycle waits before it starts // The number of frames the color-cycle waits before it starts
_waitFrames = FramesForMillis(6000); _waitFrames = FramesForMillis(6000);
// Every pixel is created after pixelWaitFrames frames, which is increased in the loop. // Every pixel is created after pixelWaitFrames frames, which is increased in the loop.
var pixelWaitFrames = FramesForMillis(2000); var pixelWaitFrames = FramesForMillis(2000);
// Create pixels // Create pixels
for (var index = 0; index < _gSpots.Count; index++) for (var index = 0; index < _gSpots.Count; index++)
{ {
// Read the pixels in the order of the flow // Read the pixels in the order of the flow
var gSpot = _gSpots[_flowOrder[index]]; var gSpot = _gSpots[_flowOrder[index]];
// Create the animation, first we do nothing (on the final destination) // Create the animation, first we do nothing (on the final destination)
RectangleAnimator pixelAnimation; RectangleAnimator pixelAnimation;
// Make the pixel grom from the middle, if this offset isn't used it looks like it's shifted // Make the pixel grom from the middle, if this offset isn't used it looks like it's shifted
var offset = (w - 2) / 2; var offset = (w - 2) / 2;
// If the optimize for Terminal Server is set we make the animation without much ado // If the optimize for Terminal Server is set we make the animation without much ado
if (IsTerminalServerSession) if (IsTerminalServerSession)
{ {
// No animation // No animation
pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), 1, EasingTypes.Cubic); pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), 1, EasingTypes.Cubic);
} }
else else
{ {
// Create the animation, first we do nothing (on the final destination) // Create the animation, first we do nothing (on the final destination)
var standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); var standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0);
pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingTypes.Quintic); pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingTypes.Quintic);
// And than we size to the wanted size. // And than we size to the wanted size.
pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), frames); pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, w - 2, w - 2), frames);
} }
// Increase the wait frames // Increase the wait frames
pixelWaitFrames += FramesForMillis(100); pixelWaitFrames += FramesForMillis(100);
// Add to the list of to be animated pixels // Add to the list of to be animated pixels
_pixels.Add(pixelAnimation); _pixels.Add(pixelAnimation);
// Add a color to the list for this pixel. // Add a color to the list for this pixel.
_pixelColors.Add(_pixelColor); _pixelColors.Add(_pixelColor);
} }
// Make sure the frame "loop" knows we have to animate // Make sure the frame "loop" knows we have to animate
_hasAnimationsLeft = true; _hasAnimationsLeft = true;
// Pixel Color cycle colors, here we use a pre-animated loop which stores the values. // Pixel Color cycle colors, here we use a pre-animated loop which stores the values.
var pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingTypes.Quadratic); var pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingTypes.Quadratic);
pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingTypes.Quadratic, EasingModes.EaseOut); pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingTypes.Quadratic, EasingModes.EaseOut);
do do
{ {
_colorFlow.Add(pixelColorAnimator.Current); _colorFlow.Add(pixelColorAnimator.Current);
pixelColorAnimator.Next(); pixelColorAnimator.Next();
} while (pixelColorAnimator.HasNext); } while (pixelColorAnimator.HasNext);
// color animation for the background // color animation for the background
_backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000)); _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000));
} }
/// <summary> /// <summary>
/// Cleanup all the allocated resources /// Cleanup all the allocated resources
/// </summary> /// </summary>
private void Cleanup(object sender, EventArgs e) private void Cleanup(object sender, EventArgs e)
{ {
if (_bitmap != null) if (_bitmap != null)
{ {
_bitmap.Dispose(); _bitmap.Dispose();
_bitmap = null; _bitmap = null;
} }
_dpiSubscription.Dispose(); _dpiSubscription.Dispose();
} }
/// <summary> /// <summary>
/// This is called when a link is clicked /// This is called when a link is clicked
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e)
{ {
if (!(sender is LinkLabel linkLabel)) if (!(sender is LinkLabel linkLabel))
{ {
return; return;
} }
try try
{ {
linkLabel.LinkVisited = true; linkLabel.LinkVisited = true;
Process.Start(linkLabel.Text); Process.Start(linkLabel.Text);
} }
catch (Exception) catch (Exception)
{ {
MessageBox.Show(string.Format(_greenshotlanguage.ErrorOpenlink, linkLabel.Text), _greenshotlanguage.Error); MessageBox.Show(string.Format(_greenshotlanguage.ErrorOpenlink, linkLabel.Text), _greenshotlanguage.Error);
} }
} }
/// <summary> /// <summary>
/// Called from the AnimatingForm, for every frame /// Called from the AnimatingForm, for every frame
/// </summary> /// </summary>
protected override void Animate() protected override void Animate()
{ {
if (_bitmap == null) if (_bitmap == null)
{ {
return; return;
} }
if (!IsTerminalServerSession) if (!IsTerminalServerSession)
{ {
// Color cycle // Color cycle
if (_waitFrames != 0) if (_waitFrames != 0)
{ {
_waitFrames--; _waitFrames--;
// Check if there is something else to do, if not we return so we don't occupy the CPU // Check if there is something else to do, if not we return so we don't occupy the CPU
if (!_hasAnimationsLeft) if (!_hasAnimationsLeft)
{ {
return; return;
} }
} }
else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) else if (_scrollCount < _pixelColors.Count + _colorFlow.Count)
{ {
// Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle.
for (var index = _pixelColors.Count - 1; index > 0; index--) for (var index = _pixelColors.Count - 1; index > 0; index--)
{ {
_pixelColors[index] = _pixelColors[index - 1]; _pixelColors[index] = _pixelColors[index - 1];
} }
// Keep adding from the colors to cycle until there is nothing left // Keep adding from the colors to cycle until there is nothing left
if (_colorIndex < _colorFlow.Count) if (_colorIndex < _colorFlow.Count)
{ {
_pixelColors[0] = _colorFlow[_colorIndex++]; _pixelColors[0] = _colorFlow[_colorIndex++];
} }
_scrollCount++; _scrollCount++;
} }
else else
{ {
// Reset values, wait X time for the next one // Reset values, wait X time for the next one
_waitFrames = FramesForMillis(3000 + _rand.Next(35000)); _waitFrames = FramesForMillis(3000 + _rand.Next(35000));
_colorIndex = 0; _colorIndex = 0;
_scrollCount = 0; _scrollCount = 0;
// Check if there is something else to do, if not we return so we don't occupy the CPU // Check if there is something else to do, if not we return so we don't occupy the CPU
if (!_hasAnimationsLeft) if (!_hasAnimationsLeft)
{ {
return; return;
} }
} }
} }
else if (!_hasAnimationsLeft) else if (!_hasAnimationsLeft)
{ {
return; return;
} }
// Draw the "G" // Draw the "G"
using (var graphics = Graphics.FromImage(_bitmap)) using (var graphics = Graphics.FromImage(_bitmap))
{ {
graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.Clear(_backgroundAnimation.Next()); graphics.Clear(_backgroundAnimation.Next());
graphics.TranslateTransform(2, -2); graphics.TranslateTransform(2, -2);
graphics.RotateTransform(20); graphics.RotateTransform(20);
using (var brush = new SolidBrush(_pixelColor)) using (var brush = new SolidBrush(_pixelColor))
{ {
var index = 0; var index = 0;
// We asume there is nothing to animate in the next Animate loop // We asume there is nothing to animate in the next Animate loop
_hasAnimationsLeft = false; _hasAnimationsLeft = false;
// Pixels of the G // Pixels of the G
foreach (var pixel in _pixels) foreach (var pixel in _pixels)
{ {
brush.Color = _pixelColors[index++]; brush.Color = _pixelColors[index++];
graphics.FillEllipse(brush, pixel.Current); graphics.FillEllipse(brush, pixel.Current);
// If a pixel still has frames left, the hasAnimationsLeft will be true // If a pixel still has frames left, the hasAnimationsLeft will be true
_hasAnimationsLeft = _hasAnimationsLeft || pixel.HasNext; _hasAnimationsLeft = _hasAnimationsLeft || pixel.HasNext;
pixel.Next(); pixel.Next();
} }
} }
} }
pictureBox1.Invalidate(); pictureBox1.Invalidate();
} }
/// <summary> /// <summary>
/// CmdKey handler /// CmdKey handler
/// </summary> /// </summary>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <param name="keyData"></param> /// <param name="keyData"></param>
/// <returns></returns> /// <returns></returns>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{ {
try try
{ {
switch (keyData) switch (keyData)
{ {
case Keys.Escape: case Keys.Escape:
DialogResult = DialogResult.Cancel; DialogResult = DialogResult.Cancel;
break; break;
case Keys.E: case Keys.E:
MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); MessageBox.Show(EnvironmentInfo.EnvironmentToString(true));
break; break;
case Keys.L: case Keys.L:
// TODO: Open the log file // TODO: Open the log file
/* /*
try try
{ {
if (File.Exists(MainForm.LogFileLocation)) if (File.Exists(MainForm.LogFileLocation))
{ {
using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) using (Process.Start("\"" + MainForm.LogFileLocation + "\""))
{ {
// nothing to do, just using dispose to cleanup // nothing to do, just using dispose to cleanup
} }
} }
else else
{ {
MessageBox.Show("Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); MessageBox.Show("Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation);
} }
} }
catch (Exception) catch (Exception)
{ {
MessageBox.Show("Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, "Error opening greeenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); MessageBox.Show("Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, "Error opening greeenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
} }
*/ */
break; break;
// TODO: Open configuration location // TODO: Open configuration location
// case Keys.I: // case Keys.I:
//try //try
//{ //{
// using (Process.Start("\"" + IniConfig.Current.IniLocation + "\"")) // using (Process.Start("\"" + IniConfig.Current.IniLocation + "\""))
// { // {
// // Ignore // // Ignore
// } // }
//} //}
//catch (Exception) //catch (Exception)
//{ //{
// MessageBox.Show("Couldn't open the greenshot.ini, it's located here: " + IniConfig.Current.IniLocation, "Error opening greeenshot.ini", MessageBoxButtons.OK, // MessageBox.Show("Couldn't open the greenshot.ini, it's located here: " + IniConfig.Current.IniLocation, "Error opening greeenshot.ini", MessageBoxButtons.OK,
// MessageBoxIcon.Asterisk); // MessageBoxIcon.Asterisk);
//} //}
//break; //break;
default: default:
return base.ProcessCmdKey(ref msg, keyData); return base.ProcessCmdKey(ref msg, keyData);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error().WriteLine(ex, $"Error handling key '{keyData}'"); Log.Error().WriteLine(ex, $"Error handling key '{keyData}'");
} }
return true; return true;
} }
} }
} }