Skip to content

Commit a0179b5

Browse files
committed
Add "Minimum reading speed to keep time stat increasing (in Characters Per Minute)" option
Change "Stop increasing time stat when minimized" option to "Stop increasing time and read character stats when minimized"
1 parent 174c73c commit a0179b5

13 files changed

+292
-220
lines changed

JL.Core/Config/CoreConfigManager.cs

+2-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public sealed class CoreConfigManager
2424
public Uri WebSocketUri { get; private set; } = new("ws://127.0.0.1:6677");
2525
public bool CheckForJLUpdatesOnStartUp { get; private set; } = true;
2626
public bool TrackTermLookupCounts { get; private set; } // = false;
27+
public int MinCharactersPerMinuteBeforeStoppingTimeTracking { get; private set; } = 60;
2728

2829
private CoreConfigManager()
2930
{
@@ -120,16 +121,6 @@ public void ApplyPreferences(SqliteConnection connection)
120121
TextBoxRemoveNewlines = ConfigDBManager.GetValueFromConfig(connection, TextBoxRemoveNewlines, nameof(TextBoxRemoveNewlines), bool.TryParse);
121122
CheckForJLUpdatesOnStartUp = ConfigDBManager.GetValueFromConfig(connection, CheckForJLUpdatesOnStartUp, nameof(CheckForJLUpdatesOnStartUp), bool.TryParse);
122123
CaptureTextFromClipboard = ConfigDBManager.GetValueFromConfig(connection, CaptureTextFromClipboard, nameof(CaptureTextFromClipboard), bool.TryParse);
123-
124-
if (!CaptureTextFromWebSocket && !CaptureTextFromClipboard)
125-
{
126-
StatsUtils.StatsStopWatch.Stop();
127-
StatsUtils.StopStatsTimer();
128-
}
129-
else
130-
{
131-
StatsUtils.StatsStopWatch.Start();
132-
StatsUtils.StartStatsTimer();
133-
}
124+
MinCharactersPerMinuteBeforeStoppingTimeTracking = ConfigDBManager.GetValueFromConfig(connection, MinCharactersPerMinuteBeforeStoppingTimeTracking, nameof(MinCharactersPerMinuteBeforeStoppingTimeTracking), int.TryParse);
134125
}
135126
}

JL.Core/Network/Networking.cs

+5-8
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,12 @@ public static async Task CheckForJLUpdates(bool isAutoCheck)
104104
s_updatingJL = false;
105105
}
106106

107-
internal static void StartUpdaterTimer()
107+
internal static void InitializeUpdaterTimer()
108108
{
109-
if (!s_updaterTimer.Enabled)
110-
{
111-
s_updaterTimer.Interval = TimeSpan.FromHours(12).TotalMilliseconds;
112-
s_updaterTimer.Elapsed += CheckForUpdates;
113-
s_updaterTimer.AutoReset = true;
114-
s_updaterTimer.Enabled = true;
115-
}
109+
s_updaterTimer.Interval = TimeSpan.FromHours(12).TotalMilliseconds;
110+
s_updaterTimer.Elapsed += CheckForUpdates;
111+
s_updaterTimer.AutoReset = true;
112+
s_updaterTimer.Enabled = true;
116113
}
117114

118115
// ReSharper disable once AsyncVoidMethod

JL.Core/Network/WebSocketUtils.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ private static void ListenWebSocket(CancellationToken cancellationToken)
7878
{
7979
if (coreConfigManager is { AutoReconnectToWebSocket: false, CaptureTextFromClipboard: false })
8080
{
81-
StatsUtils.StatsStopWatch.Stop();
82-
StatsUtils.StopStatsTimer();
81+
StatsUtils.StopTimeStatStopWatch();
8382
}
8483

8584
if (coreConfigManager.CaptureTextFromWebSocket && !cancellationToken.IsCancellationRequested)
@@ -99,8 +98,7 @@ private static void ListenWebSocket(CancellationToken cancellationToken)
9998
{
10099
if (!coreConfigManager.CaptureTextFromClipboard)
101100
{
102-
StatsUtils.StatsStopWatch.Stop();
103-
StatsUtils.StopStatsTimer();
101+
StatsUtils.StopTimeStatStopWatch();
104102
}
105103

106104
if (coreConfigManager.CaptureTextFromWebSocket && !cancellationToken.IsCancellationRequested)

JL.Core/Statistics/StatsUtils.cs

+70-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Diagnostics;
2-
using System.Text.Json.Serialization;
32
using System.Timers;
43
using JL.Core.Config;
54
using JL.Core.Utilities;
@@ -10,41 +9,94 @@ namespace JL.Core.Statistics;
109

1110
public static class StatsUtils
1211
{
13-
[JsonIgnore] public static Stats SessionStats { get; } = new();
14-
[JsonIgnore] public static Stats ProfileLifetimeStats { get; set; } = new();
15-
[JsonIgnore] public static Stats LifetimeStats { get; internal set; } = new();
12+
public static Stats SessionStats { get; } = new();
13+
public static Stats ProfileLifetimeStats { get; set; } = new();
14+
public static Stats LifetimeStats { get; internal set; } = new();
1615

17-
public static Stopwatch StatsStopWatch { get; } = new();
16+
public static Stopwatch TimeStatStopWatch { get; } = new();
1817
private static Timer StatsTimer { get; } = new();
18+
private static Timer IdleTimeTimer { get; } = new()
19+
{
20+
AutoReset = false
21+
};
22+
23+
private static int s_textLength; // = 0
1924

20-
public static void StartStatsTimer()
25+
static StatsUtils()
2126
{
22-
if (!StatsTimer.Enabled)
27+
IdleTimeTimer.Elapsed += IdleTimeTimer_OnTimedEvent;
28+
StatsTimer.Elapsed += StatsTimer_OnTimedEvent;
29+
}
30+
31+
public static void InitializeStatsTimer()
32+
{
33+
StatsTimer.Interval = TimeSpan.FromMinutes(5).TotalMilliseconds;
34+
StatsTimer.AutoReset = true;
35+
StatsTimer.Enabled = true;
36+
}
37+
38+
public static void InitializeIdleTimeTimer()
39+
{
40+
SetIdleTimeTimerInterval(s_textLength);
41+
}
42+
43+
public static void SetIdleTimeTimerInterval(int textLength)
44+
{
45+
s_textLength = textLength;
46+
double minReadingSpeedThreshold = CoreConfigManager.Instance.MinCharactersPerMinuteBeforeStoppingTimeTracking;
47+
if (minReadingSpeedThreshold > 0 && textLength > 0 && TimeStatStopWatch.IsRunning)
48+
{
49+
IdleTimeTimer.Interval = TimeSpan.FromMinutes(textLength / minReadingSpeedThreshold).TotalMilliseconds;
50+
IdleTimeTimer.Enabled = true;
51+
}
52+
else
2353
{
24-
StatsTimer.Interval = TimeSpan.FromMinutes(5).TotalMilliseconds;
25-
StatsTimer.Elapsed += OnTimedEvent;
26-
StatsTimer.AutoReset = true;
27-
StatsTimer.Enabled = true;
54+
IdleTimeTimer.Enabled = false;
2855
}
2956
}
3057

31-
public static void StopStatsTimer()
58+
public static void StartTimeStatStopWatch()
3259
{
33-
StatsTimer.Enabled = false;
60+
TimeStatStopWatch.Start();
61+
62+
// Restarts the timer
63+
// This is faster than setting the Enabled property to false and then true
64+
IdleTimeTimer.Interval = IdleTimeTimer.Interval;
65+
IdleTimeTimer.Enabled = true;
66+
}
67+
68+
public static void StopTimeStatStopWatch()
69+
{
70+
TimeStatStopWatch.Stop();
71+
IdleTimeTimer.Enabled = false;
72+
}
73+
74+
public static void StopIdleItemTimer()
75+
{
76+
IdleTimeTimer.Enabled = false;
77+
}
78+
79+
private static void IdleTimeTimer_OnTimedEvent(object? sender, ElapsedEventArgs e)
80+
{
81+
if (TimeStatStopWatch.IsRunning)
82+
{
83+
IncrementStat(StatType.Time, TimeStatStopWatch.ElapsedTicks);
84+
TimeStatStopWatch.Reset();
85+
}
3486
}
3587

36-
private static void OnTimedEvent(object? sender, ElapsedEventArgs e)
88+
private static void StatsTimer_OnTimedEvent(object? sender, ElapsedEventArgs e)
3789
{
38-
IncrementStat(StatType.Time, StatsStopWatch.ElapsedTicks);
90+
IncrementStat(StatType.Time, TimeStatStopWatch.ElapsedTicks);
3991

40-
if (StatsStopWatch.IsRunning)
92+
if (TimeStatStopWatch.IsRunning)
4193
{
42-
StatsStopWatch.Restart();
94+
TimeStatStopWatch.Restart();
4395
}
4496

4597
else
4698
{
47-
StatsStopWatch.Reset();
99+
TimeStatStopWatch.Reset();
48100
}
49101

50102
using SqliteConnection connection = ConfigDBManager.CreateReadWriteDBConnection();

JL.Core/Utilities/DBUtils.cs

+5-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ namespace JL.Core.Utilities;
1313
public static class DBUtils
1414
{
1515
private static readonly Timer s_optimizePragmaTimer = new();
16-
1716
internal static FrozenDictionary<string, string> DictDBPaths { get; set; } = FrozenDictionary<string, string>.Empty;
1817
internal static FrozenDictionary<string, string> FreqDBPaths { get; set; } = FrozenDictionary<string, string>.Empty;
1918

@@ -51,15 +50,12 @@ public static string GetFreqDBPath(string dbName)
5150
: $"{Path.Join(s_freqDBFolderPath, dbName)}.sqlite";
5251
}
5352

54-
internal static void StartOptimizePragmaTimer()
53+
internal static void InitializeOptimizePragmaTimer()
5554
{
56-
if (!s_optimizePragmaTimer.Enabled)
57-
{
58-
s_optimizePragmaTimer.Interval = TimeSpan.FromHours(1).TotalMilliseconds;
59-
s_optimizePragmaTimer.Elapsed += SendOptimizePragmaToAllDBs;
60-
s_optimizePragmaTimer.AutoReset = true;
61-
s_optimizePragmaTimer.Enabled = true;
62-
}
55+
s_optimizePragmaTimer.Interval = TimeSpan.FromHours(1).TotalMilliseconds;
56+
s_optimizePragmaTimer.Elapsed += SendOptimizePragmaToAllDBs;
57+
s_optimizePragmaTimer.AutoReset = true;
58+
s_optimizePragmaTimer.Enabled = true;
6359
}
6460

6561
private static void SendOptimizePragmaToAllDBs(object? sender, ElapsedEventArgs e)

JL.Core/Utilities/Utils.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,9 @@ internal static string GetMd5String(ReadOnlySpan<byte> bytes)
120120

121121
public static async Task CoreInitialize()
122122
{
123-
Networking.StartUpdaterTimer();
124-
125-
StatsUtils.StartStatsTimer();
126-
StatsUtils.StatsStopWatch.Start();
127-
128-
DBUtils.StartOptimizePragmaTimer();
123+
Networking.InitializeUpdaterTimer();
124+
StatsUtils.InitializeStatsTimer();
125+
DBUtils.InitializeOptimizePragmaTimer();
129126

130127
_ = Directory.CreateDirectory(ProfileUtils.ProfileFolderPath);
131128
_ = Directory.CreateDirectory(DBUtils.s_dictDBFolderPath);

JL.Windows/ConfigManager.cs

+20-5
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ internal sealed class ConfigManager
196196
public string BrowserPath { get; private set; } = "";
197197
public bool DisableHotkeys { get; set; } // = false;
198198
public bool GlobalHotKeys { get; private set; } = true;
199-
public bool StopIncreasingTimeStatWhenMinimized { get; private set; } = true;
199+
public bool StopIncreasingTimeAndCharStatsWhenMinimized { get; private set; } // = false;
200200
public bool StripPunctuationBeforeCalculatingCharacterCount { get; private set; } = true;
201201
public bool MineToFileInsteadOfAnki { get; private set; } // = false;
202202
public bool AutoAdjustFontSizesOnResolutionChange { get; private set; } // = false;
@@ -317,7 +317,7 @@ public void ApplyPreferences(SqliteConnection connection)
317317
HighlightLongestMatch = ConfigDBManager.GetValueFromConfig(connection, HighlightLongestMatch, nameof(HighlightLongestMatch), bool.TryParse);
318318
AutoPlayAudio = ConfigDBManager.GetValueFromConfig(connection, AutoPlayAudio, nameof(AutoPlayAudio), bool.TryParse);
319319
GlobalHotKeys = ConfigDBManager.GetValueFromConfig(connection, GlobalHotKeys, nameof(GlobalHotKeys), bool.TryParse);
320-
StopIncreasingTimeStatWhenMinimized = ConfigDBManager.GetValueFromConfig(connection, StopIncreasingTimeStatWhenMinimized, nameof(StopIncreasingTimeStatWhenMinimized), bool.TryParse);
320+
StopIncreasingTimeAndCharStatsWhenMinimized = ConfigDBManager.GetValueFromConfig(connection, StopIncreasingTimeAndCharStatsWhenMinimized, nameof(StopIncreasingTimeAndCharStatsWhenMinimized), bool.TryParse);
321321
MineToFileInsteadOfAnki = ConfigDBManager.GetValueFromConfig(connection, MineToFileInsteadOfAnki, nameof(MineToFileInsteadOfAnki), bool.TryParse);
322322
AlwaysOnTop = ConfigDBManager.GetValueFromConfig(connection, AlwaysOnTop, nameof(AlwaysOnTop), bool.TryParse);
323323
mainWindow.Topmost = AlwaysOnTop;
@@ -534,6 +534,17 @@ public void ApplyPreferences(SqliteConnection connection)
534534
WinApi.UnregisterAllGlobalHotKeys(mainWindow.WindowHandle);
535535
KeyGestureUtils.GlobalKeyGestureNameToKeyGestureDict.Clear();
536536

537+
if ((!StopIncreasingTimeAndCharStatsWhenMinimized || mainWindow.WindowState is not WindowState.Minimized)
538+
&& (coreConfigManager.CaptureTextFromClipboard || coreConfigManager.CaptureTextFromWebSocket))
539+
{
540+
StatsUtils.StartTimeStatStopWatch();
541+
StatsUtils.InitializeIdleTimeTimer();
542+
}
543+
else
544+
{
545+
StatsUtils.StopTimeStatStopWatch();
546+
}
547+
537548
DisableHotkeysKeyGesture = KeyGestureUtils.GetKeyGestureFromConfig(connection, nameof(DisableHotkeysKeyGesture), DisableHotkeysKeyGesture);
538549
MiningModeKeyGesture = KeyGestureUtils.GetKeyGestureFromConfig(connection, nameof(MiningModeKeyGesture), MiningModeKeyGesture);
539550
PlayAudioKeyGesture = KeyGestureUtils.GetKeyGestureFromConfig(connection, nameof(PlayAudioKeyGesture), PlayAudioKeyGesture);
@@ -882,7 +893,7 @@ public void LoadPreferenceWindow(PreferencesWindow preferenceWindow)
882893
preferenceWindow.CheckForJLUpdatesOnStartUpCheckBox.IsChecked = coreConfigManager.CheckForJLUpdatesOnStartUp;
883894
preferenceWindow.TrackTermLookupCountsCheckBox.IsChecked = coreConfigManager.TrackTermLookupCounts;
884895
preferenceWindow.GlobalHotKeysCheckBox.IsChecked = GlobalHotKeys;
885-
preferenceWindow.StopIncreasingTimeStatWhenMinimizedCheckBox.IsChecked = StopIncreasingTimeStatWhenMinimized;
896+
preferenceWindow.StopIncreasingTimeAndCharStatsWhenMinimizedCheckBox.IsChecked = StopIncreasingTimeAndCharStatsWhenMinimized;
886897
preferenceWindow.StripPunctuationBeforeCalculatingCharacterCountCheckBox.IsChecked = StripPunctuationBeforeCalculatingCharacterCount;
887898
preferenceWindow.MineToFileInsteadOfAnkiCheckBox.IsChecked = MineToFileInsteadOfAnki;
888899
preferenceWindow.AlwaysOnTopCheckBox.IsChecked = AlwaysOnTop;
@@ -981,6 +992,7 @@ public void LoadPreferenceWindow(PreferencesWindow preferenceWindow)
981992
preferenceWindow.MaxDelayBetweenCopiesForMergingMatchingSequentialTextsInMillisecondsNumericUpDown.Value = MaxDelayBetweenCopiesForMergingMatchingSequentialTextsInMilliseconds;
982993
preferenceWindow.TextBoxCustomLineHeightNumericUpDown.Value = TextBoxCustomLineHeight;
983994
preferenceWindow.AutoHidePopupIfMouseIsNotOverItDelayInMillisecondsNumericUpDown.Value = AutoHidePopupIfMouseIsNotOverItDelayInMilliseconds;
995+
preferenceWindow.MinCharactersPerMinuteBeforeStoppingTimeTrackingNumericUpDown.Value = coreConfigManager.MinCharactersPerMinuteBeforeStoppingTimeTracking;
984996
preferenceWindow.DefinitionsFontSizeNumericUpDown.Value = DefinitionsFontSize;
985997
preferenceWindow.FrequencyFontSizeNumericUpDown.Value = FrequencyFontSize;
986998
preferenceWindow.PrimarySpellingFontSizeNumericUpDown.Value = PrimarySpellingFontSize;
@@ -1261,8 +1273,8 @@ public async Task SavePreferences(PreferencesWindow preferenceWindow)
12611273

12621274
ConfigDBManager.UpdateSetting(connection, nameof(GlobalHotKeys), preferenceWindow.GlobalHotKeysCheckBox.IsChecked.ToString()!);
12631275

1264-
ConfigDBManager.UpdateSetting(connection, nameof(StopIncreasingTimeStatWhenMinimized),
1265-
preferenceWindow.StopIncreasingTimeStatWhenMinimizedCheckBox.IsChecked.ToString()!);
1276+
ConfigDBManager.UpdateSetting(connection, nameof(StopIncreasingTimeAndCharStatsWhenMinimized),
1277+
preferenceWindow.StopIncreasingTimeAndCharStatsWhenMinimizedCheckBox.IsChecked.ToString()!);
12661278

12671279
ConfigDBManager.UpdateSetting(connection, nameof(StripPunctuationBeforeCalculatingCharacterCount),
12681280
preferenceWindow.StripPunctuationBeforeCalculatingCharacterCountCheckBox.IsChecked.ToString()!);
@@ -1426,6 +1438,9 @@ public async Task SavePreferences(PreferencesWindow preferenceWindow)
14261438
ConfigDBManager.UpdateSetting(connection, nameof(AutoHidePopupIfMouseIsNotOverItDelayInMilliseconds),
14271439
preferenceWindow.AutoHidePopupIfMouseIsNotOverItDelayInMillisecondsNumericUpDown.Value.ToString(CultureInfo.InvariantCulture));
14281440

1441+
ConfigDBManager.UpdateSetting(connection, nameof(CoreConfigManager.MinCharactersPerMinuteBeforeStoppingTimeTracking),
1442+
preferenceWindow.MinCharactersPerMinuteBeforeStoppingTimeTrackingNumericUpDown.Value.ToString(CultureInfo.InvariantCulture));
1443+
14291444
ConfigDBManager.UpdateSetting(connection, nameof(AutoLookupFirstTermWhenTextIsCopiedFromClipboard),
14301445
preferenceWindow.AutoLookupFirstTermWhenTextIsCopiedFromClipboardCheckBox.IsChecked.ToString()!);
14311446

0 commit comments

Comments
 (0)