Skip to content

Commit

Permalink
Merge pull request #45 from BarRaider/dev
Browse files Browse the repository at this point in the history
v1.7 Features
  • Loading branch information
BarRaider authored Jul 20, 2021
2 parents 92cd3fd + 7d45c93 commit 2e9a694
Show file tree
Hide file tree
Showing 23 changed files with 398 additions and 1,928 deletions.
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ A C# Stopwatch implementation for the Elgato Stream Deck device.

**Author's website and contact information:** [https://barraider.github.io](https://barraider.github.io)

## New in v1.6
- `Clear file on reset` mode is awesome for making the text "Disappear" from the stream on reset
- :new: `Lap Mode` - Every press records the timestamp when pressed. A long press will reset the timer and copy all the laps to the clipboard (`Ctrl-V` to see them)

## New in v1.5
- Time is written to a file of your choice so you can display the elapsed time on your stream
- File is now created immediately when you press the "Save" button
## New in v1.7
*Our faithful Stopwatch plugin coming back with a much needed overhaul:*
- Visual indication if the stopwatch is running or stopped
- User-Customizable images for Enabled/Paused states
- New `Shared Id` feature allows you to view and control the same stopwatch from different profiles and keys
- Multi-Action support (works great with the use of Shared Ids)
- Backend logic improved to keep much more accurate time keeping when running for very long periods of times

## Current functionality
- New: Long press (2 seconds) on the key to reset the stopwatch
Expand All @@ -18,6 +18,7 @@ A C# Stopwatch implementation for the Elgato Stream Deck device.
- Stopping/Starting a watch
- Option to not reset the watch after it's restarted
- Two display styles
- `Shared Id` feature allows you to view and control the same stopwatch from different profiles and keys

## Feature roadmap
Always open to more suggestions.
Expand All @@ -35,4 +36,15 @@ Please contact the developer. Contact information is available at https://barrai
## Dependencies
* Uses StreamDeck-Tools by BarRaider: [![NuGet](https://img.shields.io/nuget/v/streamdeck-tools.svg?style=flat)](https://www.nuget.org/packages/streamdeck-tools)

* Uses [Easy-PI](https://github.com/BarRaider/streamdeck-easypi) by BarRaider - Provides seamless integration with the Stream Deck PI (Property Inspector)
* Uses [Easy-PI](https://github.com/BarRaider/streamdeck-easypi) by BarRaider - Provides seamless integration with the Stream Deck PI (Property Inspector)

## Change Log


## New in v1.6
- `Clear file on reset` mode is awesome for making the text "Disappear" from the stream on reset
- :new: `Lap Mode` - Every press records the timestamp when pressed. A long press will reset the timer and copy all the laps to the clipboard (`Ctrl-V` to see them)

## New in v1.5
- Time is written to a file of your choice so you can display the elapsed time on your stream
- File is now created immediately when you press the "Save" button
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using BarRaider.SdTools;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Stopwatch.Backend;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;

namespace Stopwatch
namespace Stopwatch.Actions
{
[PluginActionId("com.barraider.stopwatch")]
public class StopwatchTimerAction : PluginBase
Expand All @@ -31,7 +34,10 @@ public static PluginSettings CreateDefaultSettings()
Multiline = false,
ClearFileOnReset = false,
LapMode = false,
FileName = String.Empty
FileName = String.Empty,
SharedId = String.Empty,
PauseImageFile = String.Empty,
EnabledImageFile = String.Empty
};

return instance;
Expand All @@ -51,18 +57,38 @@ public static PluginSettings CreateDefaultSettings()

[JsonProperty(PropertyName = "lapMode")]
public bool LapMode { get; set; }

[JsonProperty(PropertyName = "sharedId")]
public string SharedId { get; set; }

[FilenameProperty]
[JsonProperty(PropertyName = "pauseImageFile")]
public string PauseImageFile { get; set; }

[FilenameProperty]
[JsonProperty(PropertyName = "enabledImageFile")]
public string EnabledImageFile { get; set; }

}

#region Private members

private const int RESET_COUNTER_KEYPRESS_LENGTH = 1000;
private const int RESET_COUNTER_KEYPRESS_LENGTH = 600;
private readonly string[] DEFAULT_IMAGES = new string[]
{
@"images\bg@2x.png",
@"images\bgEnabled.png"
};

private readonly PluginSettings settings;
private bool keyPressed = false;
private bool longKeyPress = false;
private DateTime keyPressStart;
private readonly string stopwatchId;
private string stopwatchId;
private readonly System.Timers.Timer tmrOnTick = new System.Timers.Timer();
private Image pauseImage;
private Image enabledImage;


#endregion

Expand All @@ -79,27 +105,36 @@ public StopwatchTimerAction(SDConnection connection, InitialPayload payload) : b
{
this.settings = payload.Settings.ToObject<PluginSettings>();
}
stopwatchId = Connection.ContextId;
InitializeSettings();
Connection.OnSendToPlugin += Connection_OnSendToPlugin;

tmrOnTick.Interval = 250;
tmrOnTick.Elapsed += TmrOnTick_Elapsed;
tmrOnTick.Start();
}


public override void Dispose()
{
tmrOnTick.Stop();
Connection.OnSendToPlugin -= Connection_OnSendToPlugin;
Logger.Instance.LogMessage(TracingLevel.INFO, "Destructor called");
}

public override void ReceivedSettings(ReceivedSettingsPayload payload)
{
string fileName = settings.FileName;
// New in StreamDeck-Tools v2.0:
Tools.AutoPopulateSettings(settings, payload.Settings);

InitializeSettings();
if (fileName != settings.FileName)
{
StopwatchManager.Instance.TouchTimerFile(settings.FileName);
}
SaveSettings();
}

public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
{}
{ }


public override void KeyPressed(KeyPayload payload)
Expand All @@ -111,6 +146,12 @@ public override void KeyPressed(KeyPayload payload)

Logger.Instance.LogMessage(TracingLevel.INFO, "Key Pressed");

if (payload.IsInMultiAction)
{
HandleMultiActionKeyPress(payload.UserDesiredState);
return;
}

if (StopwatchManager.Instance.IsStopwatchEnabled(stopwatchId)) // Stopwatch is already running
{
if (settings.LapMode)
Expand All @@ -124,12 +165,7 @@ public override void KeyPressed(KeyPayload payload)
}
else // Stopwatch is already paused
{
if (!settings.ResumeOnClick)
{
ResetCounter();
}

ResumeStopwatch();
HandleStopwatchResume();
}
}

Expand All @@ -142,11 +178,6 @@ public override void KeyReleased(KeyPayload payload)
// Using timer instead
public override void OnTick() { }

public override void Dispose()
{
Logger.Instance.LogMessage(TracingLevel.INFO, "Destructor called");
}

#endregion

#region Private methods
Expand Down Expand Up @@ -205,10 +236,10 @@ private void SaveToClipboard(string str)
t.Join();
}


private void PauseStopwatch()
{
Stopwatch.StopwatchManager.Instance.StopStopwatch(stopwatchId);
StopwatchManager.Instance.StopStopwatch(stopwatchId);
}

private string SecondsToReadableFormat(long total, string delimiter, bool secondsOnNewLine)
Expand All @@ -232,8 +263,130 @@ private async void TmrOnTick_Elapsed(object sender, ElapsedEventArgs e)

long total = StopwatchManager.Instance.GetStopwatchTime(stopwatchId);
await Connection.SetTitleAsync(SecondsToReadableFormat(total, delimiter, true));
await Connection.SetImageAsync(StopwatchManager.Instance.IsStopwatchEnabled(stopwatchId) ? enabledImage : pauseImage);
}
private Task SaveSettings()
{
return Connection.SetSettingsAsync(JObject.FromObject(settings));
}

private void InitializeSettings()
{
if (String.IsNullOrWhiteSpace(settings.SharedId))
{
stopwatchId = Connection.ContextId;
}
else
{
stopwatchId = settings.SharedId;
}

PrefetchImages();
}

private void Connection_OnSendToPlugin(object sender, BarRaider.SdTools.Wrappers.SDEventReceivedEventArgs<BarRaider.SdTools.Events.SendToPlugin> e)
{
var payload = e.Event.Payload;

Logger.Instance.LogMessage(TracingLevel.INFO, "OnSendToPlugin called");
if (payload["property_inspector"] != null)
{
switch (payload["property_inspector"].ToString().ToLowerInvariant())
{
case "loadsavepicker":
string propertyName = (string)payload["property_name"];
string pickerTitle = (string)payload["picker_title"];
string pickerFilter = (string)payload["picker_filter"];
string fileName = PickersUtil.Pickers.SaveFilePicker(pickerTitle, null, pickerFilter);
if (!string.IsNullOrEmpty(fileName))
{
if (!PickersUtil.Pickers.SetJsonPropertyValue(settings, propertyName, fileName))
{
Logger.Instance.LogMessage(TracingLevel.ERROR, "Failed to save picker value to settings");
}
SaveSettings();
}
break;
}
}
}

private void PrefetchImages()
{
if (pauseImage != null)
{
pauseImage.Dispose();
pauseImage = null;
}
pauseImage = TryLoadCustomImage(settings.PauseImageFile, DEFAULT_IMAGES[0]);

if (enabledImage != null)
{
enabledImage.Dispose();
enabledImage = null;
}
enabledImage = TryLoadCustomImage(settings.EnabledImageFile, DEFAULT_IMAGES[1]);
}

private Image TryLoadCustomImage(string customImageFileName, string defaultImageFileName)
{
if (String.IsNullOrEmpty(customImageFileName))
{
return Image.FromFile(defaultImageFileName);
}
else if (!File.Exists(customImageFileName))
{

Logger.Instance.LogMessage(TracingLevel.WARN, $"{this.GetType()} Custom image not found: {customImageFileName}");
return Image.FromFile(defaultImageFileName);
}
else
{
return Image.FromFile(customImageFileName);
}
}

private void HandleStopwatchResume()
{
if (!settings.ResumeOnClick)
{
ResetCounter();
}

ResumeStopwatch();
}

private void HandleMultiActionKeyPress(uint state)
{
switch (state) // 0 = Toggle, 1 = Start, 2 = Stop
{
case 0:
if (StopwatchManager.Instance.IsStopwatchEnabled(stopwatchId))
{
PauseStopwatch();
}
else
{
HandleStopwatchResume();
}
break;
case 1:
if (!StopwatchManager.Instance.IsStopwatchEnabled(stopwatchId))
{
HandleStopwatchResume();
}
break;
case 2:
if (StopwatchManager.Instance.IsStopwatchEnabled(stopwatchId))
{
PauseStopwatch();
}
break;
default:
Logger.Instance.LogMessage(TracingLevel.ERROR, $"{this.GetType()} HandleMultiActionKeyPress: Unsupported state {state}");
break;
}
}
#endregion
}
}
14 changes: 6 additions & 8 deletions Stopwatch/App.config
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Drawing.Common" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="CommandLine" publicKeyToken="5a870481e358d379" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.0.0" newVersion="2.6.0.0" />
<assemblyIdentity name="System.Drawing.Common" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.2" newVersion="4.0.0.2" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
</configuration>
Loading

0 comments on commit 2e9a694

Please sign in to comment.