From 8c81987d88cb6f4671030a39a8d538adbb98a1eb Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Tue, 23 Jul 2024 16:09:56 +1000 Subject: [PATCH 01/15] Fix test Update timezone in unit tests to make test pass. Test failed when I ran them in Melbourne because the hardcoded time stamps were created in my local timezone (UTC+10) while the test expectation assume the times are in Amsterdam's time zone (UTC+2) --- test/untilMorning.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/untilMorning.js b/test/untilMorning.js index 82122d0dc..5925576f4 100644 --- a/test/untilMorning.js +++ b/test/untilMorning.js @@ -71,12 +71,12 @@ describe('UntilMorning', function () { }) it('msToSunrise() returns morning time the same day', function () { - const dt = DateTime.local(2018, 8, 4, 5, 10, 0, 0) + const dt = DateTime.local(2018, 8, 4, 5, 10, 0, 0, { zone: 'Europe/Amsterdam' }) new UntilMorning(settings).msToSunrise(dt).should.be.within(60 * 60 * 1000 - 60000, 60 * 60 * 1000 + 60000) }) it('msToSunrise() returns morning time the next day', function () { - const dt = DateTime.local(2018, 8, 4, 7, 10, 0, 0) + const dt = DateTime.local(2018, 8, 4, 7, 10, 0, 0, { zone: 'Europe/Amsterdam' }) new UntilMorning(settings).msToSunrise(dt).should.be.within(23 * 60 * 60 * 1000 - 60000, 23 * 60 * 60 * 1000 + 60000) }) }) From 07ddfe2e85091b1f3944a31a829eee3370deea9e Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Tue, 23 Jul 2024 17:42:10 +1000 Subject: [PATCH 02/15] Add keyboard shortcuts for pause breaks --- app/main.js | 7 +++ app/utils/defaultSettings.js | 5 +++ app/utils/pauseBreaksShortcut.js | 44 +++++++++++++++++++ test/pauseBreaksShortcut.js | 73 ++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 app/utils/pauseBreaksShortcut.js create mode 100644 test/pauseBreaksShortcut.js diff --git a/app/main.js b/app/main.js index 6f53f1056..8ce27d463 100644 --- a/app/main.js +++ b/app/main.js @@ -8,6 +8,7 @@ const i18next = require('i18next') const Backend = require('i18next-fs-backend') const log = require('electron-log/main') const Store = require('electron-store') +const { registerPauseBreaksShortcuts } = require('./utils/pauseBreaksShortcut') process.on('uncaughtException', (err, _) => { log.error(err) @@ -261,6 +262,7 @@ async function initialize (isAppStart = true) { contributorPreferencesWindow.send('renderSettings', await settingsToSend()) } globalShortcut.unregisterAll() + registerPauseBreaksShortcuts(settings, pauseBreaks, log, globalShortcut) if (settings.get('pauseBreaksToggleShortcut') !== '') { const pauseBreaksToggleShortcut = globalShortcut.register(settings.get('pauseBreaksToggleShortcut'), () => { if (breakPlanner.isPaused) { @@ -1315,26 +1317,31 @@ function getTrayMenuTemplate () { submenu: [ { label: i18next.t('utils.minutes', { count: 30 }), + accelerator: settings.get('pauseBreaksFor30MinutesShortcut'), click: function () { pauseBreaks(1800 * 1000) } }, { label: i18next.t('main.forHour'), + accelerator: settings.get('pauseBreaksFor1HourShortcut'), click: function () { pauseBreaks(3600 * 1000) } }, { label: i18next.t('main.for2Hours'), + accelerator: settings.get('pauseBreaksFor2HoursShortcut'), click: function () { pauseBreaks(3600 * 2 * 1000) } }, { label: i18next.t('main.for5Hours'), + accelerator: settings.get('pauseBreaksFor5HoursShortcut'), click: function () { pauseBreaks(3600 * 5 * 1000) } }, { label: i18next.t('main.untilMorning'), + accelerator: settings.get('pauseBreaksUntilMorningShortcut'), click: function () { const untilMorning = new UntilMorning(settings).msToSunrise() pauseBreaks(untilMorning) diff --git a/app/utils/defaultSettings.js b/app/utils/defaultSettings.js index cda6d6ae3..d69bd02ca 100644 --- a/app/utils/defaultSettings.js +++ b/app/utils/defaultSettings.js @@ -60,6 +60,11 @@ module.exports = { appExclusionsCheckInterval: 1000, pauseForSuspendOrLock: true, pauseBreaksToggleShortcut: '', + pauseBreaksFor30MinutesShortcut: '', + pauseBreaksFor1HourShortcut: '', + pauseBreaksFor2HoursShortcut: '', + pauseBreaksFor5HoursShortcut: '', + pauseBreaksUntilMorningShortcut: '', screen: 'primary', timeToBreakInTray: false, currentTimeInBreaks: false, diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js new file mode 100644 index 000000000..b83b87db2 --- /dev/null +++ b/app/utils/pauseBreaksShortcut.js @@ -0,0 +1,44 @@ +const { UntilMorning } = require('./untilMorning') + +const intervals = { + pauseBreaksFor30MinutesShortcut: 30 * 60 * 1000, + pauseBreaksFor1HourShortcut: 3600 * 1000, + pauseBreaksFor2HoursShortcut: 2 * 3600 * 1000, + pauseBreaksFor5HoursShortcut: 5 * 3600 * 1000, + pauseBreaksUntilMorningShortcut: null +} + +function calculateInterval (name, settings) { + if (name === 'pauseBreaksUntilMorningShortcut') { + return new UntilMorning(settings).msToSunrise() + } + + return intervals[name] +} + +function setupBreak (name, shortcutText, settings, pauseBreaks, log, globalShortcut) { + const shortcut = globalShortcut.register(shortcutText, () => { + const interval = calculateInterval(name, settings) + pauseBreaks(interval) + }) + + if (shortcut) { + log.info(`Stretchly: ${name} registration successful (${shortcutText})`) + } else { + log.warn(`Stretchly: ${name} registration failed`) + } +} + +function registerPauseBreaksShortcuts (settings, pauseBreaks, log, globalShortcut) { + for (const name of Object.keys(intervals)) { + const shortcutText = settings.get(name) + if (shortcutText === '') continue + setupBreak(name, shortcutText, settings, pauseBreaks, log, globalShortcut) + } +} + +module.exports = { + calculateInterval, + registerPauseBreaksShortcuts, + setupBreak +} diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js new file mode 100644 index 000000000..26bddd349 --- /dev/null +++ b/test/pauseBreaksShortcut.js @@ -0,0 +1,73 @@ +import { vi } from 'vitest' +import { expect } from 'chai' +import { calculateInterval, registerPauseBreaksShortcuts, setupBreak } from '../app/utils/pauseBreaksShortcut' + +describe('pauseBreaksShortcut', () => { + describe('calculateInterval', () => { + it('should return correct interval for pauseBreaksFor30MinutesShortcut', () => { + const interval = calculateInterval('pauseBreaksFor30MinutesShortcut') + expect(interval).toBe(30 * 60 * 1000) + }) + + it('should return correct interval for pauseBreaksFor1HourShortcut', () => { + const interval = calculateInterval('pauseBreaksFor1HourShortcut') + expect(interval).toBe(3600 * 1000) + }) + + it('should return correct interval for pauseBreaksFor2HoursShortcut', () => { + const interval = calculateInterval('pauseBreaksFor2HoursShortcut') + expect(interval).toBe(2 * 3600 * 1000) + }) + + it('should return correct interval for pauseBreaksFor5HoursShortcut', () => { + const interval = calculateInterval('pauseBreaksFor5HoursShortcut') + expect(interval).toBe(5 * 3600 * 1000) + }) + + it('should return correct interval for pauseBreaksUntilMorningShortcut', () => { + const settings = { get: () => 6 } + const interval = calculateInterval('pauseBreaksUntilMorningShortcut', settings) + expect(interval).toBeGreaterThan(0) + expect(interval).toBeLessThan(24 * 60 * 60 * 1000) + }) + }) + + describe('setupBreak', () => { + it('should register a shortcut and call pauseBreaks with the correct interval', () => { + const globalShortcut = { register: vi.fn().mockReturnValue(true) } + const log = { info: vi.fn(), warn: vi.fn() } + const pauseBreaks = vi.fn() + + setupBreak('pauseBreaksFor30MinutesShortcut', 'Ctrl+Shift+P', null, pauseBreaks, log, globalShortcut) + + expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) + globalShortcut.register.mock.calls[0][1]() + expect(pauseBreaks).toHaveBeenCalledWith(30 * 60 * 1000) + expect(log.info).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration successful (Ctrl+Shift+P)') + }) + + it('should log a warning if shortcut registration fails', () => { + const globalShortcut = { register: vi.fn().mockReturnValue(false) } + const log = { info: vi.fn(), warn: vi.fn() } + const pauseBreaks = vi.fn() + + setupBreak('pauseBreaksFor30MinutesShortcut', 'Ctrl+Shift+P', null, pauseBreaks, log, globalShortcut) + + expect(log.warn).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration failed') + }) + }) + + describe('registerPauseBreaksShortcuts', () => { + it('should register all shortcuts from settings', () => { + const globalShortcut = { register: vi.fn().mockReturnValue(true) } + const log = { info: vi.fn(), warn: vi.fn() } + const pauseBreaks = vi.fn() + const settings = { get: vi.fn((name) => name === 'pauseBreaksFor30MinutesShortcut' ? 'Ctrl+Shift+P' : '') } + + registerPauseBreaksShortcuts(settings, pauseBreaks, log, globalShortcut) + + expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) + expect(log.info).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration successful (Ctrl+Shift+P)') + }) + }) +}) From 5947189980ac4370b95bf2a2ca141325cee8a074 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Tue, 23 Jul 2024 20:13:06 +1000 Subject: [PATCH 03/15] Document --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 4488b92ce..2dde63b47 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,18 @@ In the preferences file, set `pauseBreaksToggleShortcut` to your preferred value If you'd like to disable the shortcut, set value to empty string `""`. That's the default value as well. +#### Pause Breaks for Duration Shortcuts + +You can also set shortcuts to pause breaks for a specific duration by modifying the following values in the preferences file: + +- `pauseBreaksFor30MinutesShortcut` +- `pauseBreaksFor1HourShortcut` +- `pauseBreaksFor2HoursShortcut` +- `pauseBreaksFor5HoursShortcut` +- `pauseBreaksUntilMorningShortcut` + +If you'd like to disable the shortcuts, set value to empty string `""`. That's the default value as well. + #### Skip to the next Break Shortcut In the preferences file, set `skipToNextScheduledBreakShortcut`, `skipToNextMiniBreakShortcut`, `skipToNextLongBreakShortcut` to your preferred value. We do not validate this input, so please check [Electron's documentation](https://www.electronjs.org/docs/api/accelerator) for available values for key and modifier. When a given accelerator is already taken by other applications, this call will silently fail. This behavior is intended by operating systems, since they don't want applications to fight for global shortcuts. From ee9665f83a940e7bf1cdb40623219617803fa8df Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Tue, 23 Jul 2024 21:56:53 +1000 Subject: [PATCH 04/15] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83f3c5901..9e8c28946 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Updated flag of Belarus to White-Red-White - advanced option to show break options (Skip, Pause, Reset) in Strict mode - add autostart option for Linux +- Add keyboard shortcuts for pause breaks for duration. ### Changed - updated many translations From e41c05196c8826ddceb4901a35ee3285e0bec77e Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Wed, 24 Jul 2024 16:04:13 +1000 Subject: [PATCH 05/15] Use object parameter --- app/main.js | 9 ++++++++- app/utils/pauseBreaksShortcut.js | 14 +++++++++++--- test/pauseBreaksShortcut.js | 25 ++++++++++++++++++++++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/app/main.js b/app/main.js index 8ce27d463..e2236dae2 100644 --- a/app/main.js +++ b/app/main.js @@ -262,7 +262,14 @@ async function initialize (isAppStart = true) { contributorPreferencesWindow.send('renderSettings', await settingsToSend()) } globalShortcut.unregisterAll() - registerPauseBreaksShortcuts(settings, pauseBreaks, log, globalShortcut) + + registerPauseBreaksShortcuts({ + settings, + log, + globalShortcut, + functions: { pauseBreaks } + }) + if (settings.get('pauseBreaksToggleShortcut') !== '') { const pauseBreaksToggleShortcut = globalShortcut.register(settings.get('pauseBreaksToggleShortcut'), () => { if (breakPlanner.isPaused) { diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index b83b87db2..7a4267d86 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -16,7 +16,7 @@ function calculateInterval (name, settings) { return intervals[name] } -function setupBreak (name, shortcutText, settings, pauseBreaks, log, globalShortcut) { +function setupBreak ({ name, shortcutText, settings, pauseBreaks, log, globalShortcut }) { const shortcut = globalShortcut.register(shortcutText, () => { const interval = calculateInterval(name, settings) pauseBreaks(interval) @@ -29,11 +29,19 @@ function setupBreak (name, shortcutText, settings, pauseBreaks, log, globalShort } } -function registerPauseBreaksShortcuts (settings, pauseBreaks, log, globalShortcut) { +function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, functions }) { for (const name of Object.keys(intervals)) { const shortcutText = settings.get(name) if (shortcutText === '') continue - setupBreak(name, shortcutText, settings, pauseBreaks, log, globalShortcut) + + setupBreak({ + name, + shortcutText, + settings, + pauseBreaks: functions.pauseBreaks, + log, + globalShortcut + }) } } diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 26bddd349..cb0e4f312 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -38,7 +38,14 @@ describe('pauseBreaksShortcut', () => { const log = { info: vi.fn(), warn: vi.fn() } const pauseBreaks = vi.fn() - setupBreak('pauseBreaksFor30MinutesShortcut', 'Ctrl+Shift+P', null, pauseBreaks, log, globalShortcut) + setupBreak({ + name: 'pauseBreaksFor30MinutesShortcut', + shortcutText: 'Ctrl+Shift+P', + settings: null, + pauseBreaks, + log, + globalShortcut + }) expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) globalShortcut.register.mock.calls[0][1]() @@ -51,7 +58,14 @@ describe('pauseBreaksShortcut', () => { const log = { info: vi.fn(), warn: vi.fn() } const pauseBreaks = vi.fn() - setupBreak('pauseBreaksFor30MinutesShortcut', 'Ctrl+Shift+P', null, pauseBreaks, log, globalShortcut) + setupBreak({ + name: 'pauseBreaksFor30MinutesShortcut', + shortcutText: 'Ctrl+Shift+P', + settings: null, + pauseBreaks, + log, + globalShortcut + }) expect(log.warn).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration failed') }) @@ -64,7 +78,12 @@ describe('pauseBreaksShortcut', () => { const pauseBreaks = vi.fn() const settings = { get: vi.fn((name) => name === 'pauseBreaksFor30MinutesShortcut' ? 'Ctrl+Shift+P' : '') } - registerPauseBreaksShortcuts(settings, pauseBreaks, log, globalShortcut) + registerPauseBreaksShortcuts({ + settings, + log, + globalShortcut, + functions: { pauseBreaks } + }) expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) expect(log.info).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration successful (Ctrl+Shift+P)') From 74acca6176d1d489d7adbd63f25fd5d4939bc79b Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Wed, 24 Jul 2024 16:45:58 +1000 Subject: [PATCH 06/15] Move pauseBreaksToggleShortcut out of main.js --- app/main.js | 18 +------- app/utils/pauseBreaksShortcut.js | 28 +++++++---- test/pauseBreaksShortcut.js | 79 ++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/app/main.js b/app/main.js index e2236dae2..317472370 100644 --- a/app/main.js +++ b/app/main.js @@ -267,24 +267,10 @@ async function initialize (isAppStart = true) { settings, log, globalShortcut, - functions: { pauseBreaks } + breakPlanner, + functions: { pauseBreaks, resumeBreaks } }) - if (settings.get('pauseBreaksToggleShortcut') !== '') { - const pauseBreaksToggleShortcut = globalShortcut.register(settings.get('pauseBreaksToggleShortcut'), () => { - if (breakPlanner.isPaused) { - resumeBreaks(false) - } else { - pauseBreaks(1) - } - }) - - if (!pauseBreaksToggleShortcut) { - log.warn('Stretchly: pauseBreaksToggleShortcut registration failed') - } else { - log.info(`Stretchly: pauseBreaksToggleShortcut registration successful (${settings.get('pauseBreaksToggleShortcut')})`) - } - } if (settings.get('skipToNextScheduledBreakShortcut') !== '') { const skipToNextScheduledBreakShortcut = globalShortcut.register(settings.get('skipToNextScheduledBreakShortcut'), () => { log.info('Stretchly: skipping to next scheduled Break by shortcut') diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 7a4267d86..440d0e969 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -5,7 +5,8 @@ const intervals = { pauseBreaksFor1HourShortcut: 3600 * 1000, pauseBreaksFor2HoursShortcut: 2 * 3600 * 1000, pauseBreaksFor5HoursShortcut: 5 * 3600 * 1000, - pauseBreaksUntilMorningShortcut: null + pauseBreaksUntilMorningShortcut: null, + pauseBreaksToggleShortcut: 1 // 1 means pause indefinitely } function calculateInterval (name, settings) { @@ -16,11 +17,18 @@ function calculateInterval (name, settings) { return intervals[name] } -function setupBreak ({ name, shortcutText, settings, pauseBreaks, log, globalShortcut }) { - const shortcut = globalShortcut.register(shortcutText, () => { - const interval = calculateInterval(name, settings) - pauseBreaks(interval) - }) +function onShortcut ({ name, settings, breakPlanner, functions }) { + if (name === 'pauseBreaksToggleShortcut' && breakPlanner.isPaused) { + functions.resumeBreaks(false) + return + } + + const interval = calculateInterval(name, settings) + functions.pauseBreaks(interval) +} + +function setupBreak ({ name, shortcutText, settings, log, globalShortcut, breakPlanner, functions }) { + const shortcut = globalShortcut.register(shortcutText, () => onShortcut({ name, settings, breakPlanner, functions })) if (shortcut) { log.info(`Stretchly: ${name} registration successful (${shortcutText})`) @@ -29,7 +37,7 @@ function setupBreak ({ name, shortcutText, settings, pauseBreaks, log, globalSho } } -function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, functions }) { +function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, breakPlanner, functions }) { for (const name of Object.keys(intervals)) { const shortcutText = settings.get(name) if (shortcutText === '') continue @@ -38,15 +46,17 @@ function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, function name, shortcutText, settings, - pauseBreaks: functions.pauseBreaks, log, - globalShortcut + globalShortcut, + breakPlanner, + functions }) } } module.exports = { calculateInterval, + onShortcut, registerPauseBreaksShortcuts, setupBreak } diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index cb0e4f312..16fa8ae4e 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -1,6 +1,6 @@ import { vi } from 'vitest' import { expect } from 'chai' -import { calculateInterval, registerPauseBreaksShortcuts, setupBreak } from '../app/utils/pauseBreaksShortcut' +import { calculateInterval, registerPauseBreaksShortcuts, setupBreak, onShortcut } from '../app/utils/pauseBreaksShortcut' describe('pauseBreaksShortcut', () => { describe('calculateInterval', () => { @@ -32,6 +32,72 @@ describe('pauseBreaksShortcut', () => { }) }) + describe('onShortcut', () => { + it('calls pauseBreaks for pauseBreaksFor30MinutesShortcut', () => { + const pauseBreaks = vi.fn() + + onShortcut({ + name: 'pauseBreaksFor30MinutesShortcut', + settings: null, + breakPlanner: null, + functions: { pauseBreaks } + }) + + expect(pauseBreaks).toHaveBeenCalledWith(30 * 60 * 1000) + }) + + it('for pauseBreaksUntilMorningShortcut calls pauseBreaks with correct interval', () => { + const pauseBreaks = vi.fn() + const settings = { get: () => 6 } + + onShortcut({ + name: 'pauseBreaksUntilMorningShortcut', + settings, + breakPlanner: null, + functions: { pauseBreaks } + }) + + expect(pauseBreaks).toHaveBeenCalled() + + // Check the interval parameter passed to pauseBreaks + const intervalExpected = calculateInterval('pauseBreaksUntilMorningShortcut', settings) + const intervalActual = pauseBreaks.mock.calls[0][0] + + // expect interval to be within 1 second of expected value + expect(Math.abs(intervalActual - intervalExpected)).toBeLessThan(1000) + }) + + describe('pauseBreaksToggleShortcut', () => { + it('pauses breaks indefinitely', () => { + const pauseBreaks = vi.fn() + const breakPlanner = { isPaused: false } + + onShortcut({ + name: 'pauseBreaksToggleShortcut', + settings: null, + breakPlanner, + functions: { pauseBreaks } + }) + + expect(pauseBreaks).toHaveBeenCalledWith(1) + }) + + it('resumes breaks when they are paused', () => { + const resumeBreaks = vi.fn() + const breakPlanner = { isPaused: true } + + onShortcut({ + name: 'pauseBreaksToggleShortcut', + settings: null, + breakPlanner, + functions: { resumeBreaks } + }) + + expect(resumeBreaks).toHaveBeenCalledWith(false) + }) + }) + }) + describe('setupBreak', () => { it('should register a shortcut and call pauseBreaks with the correct interval', () => { const globalShortcut = { register: vi.fn().mockReturnValue(true) } @@ -42,9 +108,10 @@ describe('pauseBreaksShortcut', () => { name: 'pauseBreaksFor30MinutesShortcut', shortcutText: 'Ctrl+Shift+P', settings: null, - pauseBreaks, log, - globalShortcut + globalShortcut, + breakPlanner: null, + functions: { pauseBreaks } }) expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) @@ -62,9 +129,10 @@ describe('pauseBreaksShortcut', () => { name: 'pauseBreaksFor30MinutesShortcut', shortcutText: 'Ctrl+Shift+P', settings: null, - pauseBreaks, log, - globalShortcut + globalShortcut, + breakPlanner: null, + functions: { pauseBreaks } }) expect(log.warn).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration failed') @@ -82,6 +150,7 @@ describe('pauseBreaksShortcut', () => { settings, log, globalShortcut, + breakPlanner: null, functions: { pauseBreaks } }) From ebf1e51eedb81dbafab21ac17064ad8666c77ed1 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Wed, 24 Jul 2024 17:11:58 +1000 Subject: [PATCH 07/15] Move skipToNextScheduledBreakShortcut out of main.js --- app/main.js | 18 +---------- app/utils/pauseBreaksShortcut.js | 19 ++++++++++-- test/pauseBreaksShortcut.js | 52 ++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/app/main.js b/app/main.js index 317472370..ab3947ecf 100644 --- a/app/main.js +++ b/app/main.js @@ -268,25 +268,9 @@ async function initialize (isAppStart = true) { log, globalShortcut, breakPlanner, - functions: { pauseBreaks, resumeBreaks } + functions: { pauseBreaks, resumeBreaks, skipToBreak, skipToMicrobreak } }) - if (settings.get('skipToNextScheduledBreakShortcut') !== '') { - const skipToNextScheduledBreakShortcut = globalShortcut.register(settings.get('skipToNextScheduledBreakShortcut'), () => { - log.info('Stretchly: skipping to next scheduled Break by shortcut') - if (breakPlanner._scheduledBreakType === 'break') { - skipToBreak() - } else if (breakPlanner._scheduledBreakType === 'microbreak') { - skipToMicrobreak() - } - }) - - if (!skipToNextScheduledBreakShortcut) { - log.warn('Stretchly: skipToNextScheduledBreakShortcut registration failed') - } else { - log.info(`Stretchly: skipToNextScheduledBreakShortcut registration successful (${settings.get('skipToNextScheduledBreakShortcut')})`) - } - } if (settings.get('skipToNextMiniBreakShortcut') !== '') { const skipToNextMiniBreakShortcut = globalShortcut.register(settings.get('skipToNextMiniBreakShortcut'), () => { log.info('Stretchly: skipping to next Mini Break by shortcut') diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 440d0e969..56937c28f 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -6,7 +6,8 @@ const intervals = { pauseBreaksFor2HoursShortcut: 2 * 3600 * 1000, pauseBreaksFor5HoursShortcut: 5 * 3600 * 1000, pauseBreaksUntilMorningShortcut: null, - pauseBreaksToggleShortcut: 1 // 1 means pause indefinitely + pauseBreaksToggleShortcut: 1, // 1 means pause indefinitely + skipToNextScheduledBreakShortcut: null } function calculateInterval (name, settings) { @@ -17,18 +18,30 @@ function calculateInterval (name, settings) { return intervals[name] } -function onShortcut ({ name, settings, breakPlanner, functions }) { +function onShortcut ({ name, settings, log, breakPlanner, functions }) { if (name === 'pauseBreaksToggleShortcut' && breakPlanner.isPaused) { functions.resumeBreaks(false) return } + if (name === 'skipToNextScheduledBreakShortcut') { + log.info('Stretchly: skipping to next scheduled Break by shortcut') + + if (breakPlanner._scheduledBreakType === 'break') { + functions.skipToBreak() + } else if (breakPlanner._scheduledBreakType === 'microbreak') { + functions.skipToMicrobreak() + } + + return + } + const interval = calculateInterval(name, settings) functions.pauseBreaks(interval) } function setupBreak ({ name, shortcutText, settings, log, globalShortcut, breakPlanner, functions }) { - const shortcut = globalShortcut.register(shortcutText, () => onShortcut({ name, settings, breakPlanner, functions })) + const shortcut = globalShortcut.register(shortcutText, () => onShortcut({ name, settings, log, breakPlanner, functions })) if (shortcut) { log.info(`Stretchly: ${name} registration successful (${shortcutText})`) diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 16fa8ae4e..7a78a71f8 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -63,8 +63,52 @@ describe('pauseBreaksShortcut', () => { const intervalExpected = calculateInterval('pauseBreaksUntilMorningShortcut', settings) const intervalActual = pauseBreaks.mock.calls[0][0] - // expect interval to be within 1 second of expected value - expect(Math.abs(intervalActual - intervalExpected)).toBeLessThan(1000) + // expect interval to be within 10 seconds of expected value + expect(Math.abs(intervalActual - intervalExpected)).toBeLessThan(10 * 1000) + }) + + describe('skipToNextScheduledBreakShortcut', () => { + it('skips to next scheduled break', () => { + const log = { info: vi.fn() } + const skipToBreak = vi.fn() + const skipToMicrobreak = vi.fn() + const pauseBreaks = vi.fn() + const breakPlanner = { _scheduledBreakType: 'break' } + + onShortcut({ + name: 'skipToNextScheduledBreakShortcut', + settings: null, + breakPlanner, + functions: { skipToBreak, skipToMicrobreak, pauseBreaks }, + log + }) + + expect(log.info).toHaveBeenCalledWith('Stretchly: skipping to next scheduled Break by shortcut') + expect(skipToBreak).toHaveBeenCalled() + expect(skipToMicrobreak).not.toHaveBeenCalled() + expect(pauseBreaks).not.toHaveBeenCalled() + }) + + it('skips to next scheduled microbreak', () => { + const log = { info: vi.fn() } + const skipToBreak = vi.fn() + const skipToMicrobreak = vi.fn() + const pauseBreaks = vi.fn() + const breakPlanner = { _scheduledBreakType: 'microbreak' } + + onShortcut({ + name: 'skipToNextScheduledBreakShortcut', + settings: null, + breakPlanner, + functions: { skipToBreak, skipToMicrobreak, pauseBreaks }, + log + }) + + expect(log.info).toHaveBeenCalledWith('Stretchly: skipping to next scheduled Break by shortcut') + expect(skipToBreak).not.toHaveBeenCalled() + expect(skipToMicrobreak).toHaveBeenCalled() + expect(pauseBreaks).not.toHaveBeenCalled() + }) }) describe('pauseBreaksToggleShortcut', () => { @@ -84,16 +128,18 @@ describe('pauseBreaksShortcut', () => { it('resumes breaks when they are paused', () => { const resumeBreaks = vi.fn() + const pauseBreaks = vi.fn() const breakPlanner = { isPaused: true } onShortcut({ name: 'pauseBreaksToggleShortcut', settings: null, breakPlanner, - functions: { resumeBreaks } + functions: { resumeBreaks, pauseBreaks } }) expect(resumeBreaks).toHaveBeenCalledWith(false) + expect(pauseBreaks).not.toHaveBeenCalled() }) }) }) From a6367fd79ea032e30d671d9d06ee54dd8995445f Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Wed, 24 Jul 2024 17:36:32 +1000 Subject: [PATCH 08/15] More tests for registerPauseBreaksShortcuts --- test/pauseBreaksShortcut.js | 53 ++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 7a78a71f8..6baa7a4c1 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -190,7 +190,18 @@ describe('pauseBreaksShortcut', () => { const globalShortcut = { register: vi.fn().mockReturnValue(true) } const log = { info: vi.fn(), warn: vi.fn() } const pauseBreaks = vi.fn() - const settings = { get: vi.fn((name) => name === 'pauseBreaksFor30MinutesShortcut' ? 'Ctrl+Shift+P' : '') } + + const intervals = { + pauseBreaksFor30MinutesShortcut: 0, + pauseBreaksFor1HourShortcut: 1, + pauseBreaksFor2HoursShortcut: 2, + pauseBreaksFor5HoursShortcut: 3, + pauseBreaksUntilMorningShortcut: 4, + pauseBreaksToggleShortcut: 5, + skipToNextScheduledBreakShortcut: 6 + } + + const settings = { get: vi.fn((name) => intervals[name]) } registerPauseBreaksShortcuts({ settings, @@ -200,8 +211,44 @@ describe('pauseBreaksShortcut', () => { functions: { pauseBreaks } }) - expect(globalShortcut.register).toHaveBeenCalledWith('Ctrl+Shift+P', expect.any(Function)) - expect(log.info).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration successful (Ctrl+Shift+P)') + // Check shortcut registration + // ------------ + + expect(globalShortcut.register).toHaveBeenCalledTimes(7) + + for (let i = 0; i < 7; i++) { + expect(globalShortcut.register.mock.calls[i][0]).toBe(i) + } + + // Check log + // ------------ + + expect(log.info).toHaveBeenCalledTimes(7) + + for (let i = 0; i < 7; i++) { + expect(log.info.mock.calls[i][0]).toMatch(`registration successful (${i})`) + } + }) + + it('should skip empty shortcuts', () => { + const globalShortcut = { register: vi.fn().mockReturnValue(true) } + const log = { info: vi.fn(), warn: vi.fn() } + const pauseBreaks = vi.fn() + + const settings = { get: vi.fn((name) => name === 'pauseBreaksFor30MinutesShortcut' ? 'key' : '') } + + registerPauseBreaksShortcuts({ + settings, + log, + globalShortcut, + breakPlanner: null, + functions: { pauseBreaks } + }) + + expect(globalShortcut.register).toHaveBeenCalledTimes(1) + expect(globalShortcut.register).toHaveBeenCalledWith('key', expect.any(Function)) + expect(log.info).toHaveBeenCalledTimes(1) + expect(log.info).toHaveBeenCalledWith('Stretchly: pauseBreaksFor30MinutesShortcut registration successful (key)') }) }) }) From be9d70876342fbdce7a70aaa28ae440c189b66a8 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:05:43 +1000 Subject: [PATCH 09/15] Move skipToNextMiniBreakShortcut out of main.js --- app/main.js | 12 ------------ app/utils/pauseBreaksShortcut.js | 9 ++++++++- test/pauseBreaksShortcut.js | 31 ++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/main.js b/app/main.js index ab3947ecf..4141ae617 100644 --- a/app/main.js +++ b/app/main.js @@ -271,18 +271,6 @@ async function initialize (isAppStart = true) { functions: { pauseBreaks, resumeBreaks, skipToBreak, skipToMicrobreak } }) - if (settings.get('skipToNextMiniBreakShortcut') !== '') { - const skipToNextMiniBreakShortcut = globalShortcut.register(settings.get('skipToNextMiniBreakShortcut'), () => { - log.info('Stretchly: skipping to next Mini Break by shortcut') - skipToMicrobreak() - }) - - if (!skipToNextMiniBreakShortcut) { - log.warn('Stretchly: skipToNextMiniBreakShortcut registration failed') - } else { - log.info(`Stretchly: skipToNextMiniBreakShortcut registration successful (${settings.get('skipToNextMiniBreakShortcut')})`) - } - } if (settings.get('skipToNextLongBreakShortcut') !== '') { const skipToNextLongBreakShortcut = globalShortcut.register(settings.get('skipToNextLongBreakShortcut'), () => { log.info('Stretchly: skipping to next Long Break by shortcut') diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 56937c28f..59159d1f4 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -7,7 +7,8 @@ const intervals = { pauseBreaksFor5HoursShortcut: 5 * 3600 * 1000, pauseBreaksUntilMorningShortcut: null, pauseBreaksToggleShortcut: 1, // 1 means pause indefinitely - skipToNextScheduledBreakShortcut: null + skipToNextScheduledBreakShortcut: null, + skipToNextMiniBreakShortcut: null } function calculateInterval (name, settings) { @@ -36,6 +37,12 @@ function onShortcut ({ name, settings, log, breakPlanner, functions }) { return } + if (name === 'skipToNextMiniBreakShortcut') { + log.info('Stretchly: skipping to next Mini Break by shortcut') + functions.skipToMicrobreak() + return + } + const interval = calculateInterval(name, settings) functions.pauseBreaks(interval) } diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 6baa7a4c1..0e7c19d90 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -111,6 +111,26 @@ describe('pauseBreaksShortcut', () => { }) }) + describe('skipToNextMiniBreakShortcut', () => { + it('skips to next scheduled microbreak', () => { + const log = { info: vi.fn() } + const skipToMicrobreak = vi.fn() + const pauseBreaks = vi.fn() + + onShortcut({ + name: 'skipToNextMiniBreakShortcut', + settings: null, + breakPlanner: null, + functions: { skipToMicrobreak, pauseBreaks }, + log + }) + + expect(log.info).toHaveBeenCalledWith('Stretchly: skipping to next Mini Break by shortcut') + expect(skipToMicrobreak).toHaveBeenCalled() + expect(pauseBreaks).not.toHaveBeenCalled() + }) + }) + describe('pauseBreaksToggleShortcut', () => { it('pauses breaks indefinitely', () => { const pauseBreaks = vi.fn() @@ -198,7 +218,8 @@ describe('pauseBreaksShortcut', () => { pauseBreaksFor5HoursShortcut: 3, pauseBreaksUntilMorningShortcut: 4, pauseBreaksToggleShortcut: 5, - skipToNextScheduledBreakShortcut: 6 + skipToNextScheduledBreakShortcut: 6, + skipToNextMiniBreakShortcut: 7 } const settings = { get: vi.fn((name) => intervals[name]) } @@ -214,18 +235,18 @@ describe('pauseBreaksShortcut', () => { // Check shortcut registration // ------------ - expect(globalShortcut.register).toHaveBeenCalledTimes(7) + expect(globalShortcut.register).toHaveBeenCalledTimes(8) - for (let i = 0; i < 7; i++) { + for (let i = 0; i < 8; i++) { expect(globalShortcut.register.mock.calls[i][0]).toBe(i) } // Check log // ------------ - expect(log.info).toHaveBeenCalledTimes(7) + expect(log.info).toHaveBeenCalledTimes(8) - for (let i = 0; i < 7; i++) { + for (let i = 0; i < 8; i++) { expect(log.info.mock.calls[i][0]).toMatch(`registration successful (${i})`) } }) From eb111ae84b7dbd1aa323f0c3582c254d6630fc35 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:09:14 +1000 Subject: [PATCH 10/15] Move skipToNextLongBreakShortcut out of main.js --- app/main.js | 12 ------------ app/utils/pauseBreaksShortcut.js | 9 ++++++++- test/pauseBreaksShortcut.js | 31 ++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/main.js b/app/main.js index 4141ae617..7174931a5 100644 --- a/app/main.js +++ b/app/main.js @@ -271,18 +271,6 @@ async function initialize (isAppStart = true) { functions: { pauseBreaks, resumeBreaks, skipToBreak, skipToMicrobreak } }) - if (settings.get('skipToNextLongBreakShortcut') !== '') { - const skipToNextLongBreakShortcut = globalShortcut.register(settings.get('skipToNextLongBreakShortcut'), () => { - log.info('Stretchly: skipping to next Long Break by shortcut') - skipToBreak() - }) - - if (!skipToNextLongBreakShortcut) { - log.warn('Stretchly: skipToNextLongBreakShortcut registration failed') - } else { - log.info(`Stretchly: skipToNextLongBreakShortcut registration successful (${settings.get('skipToNextLongBreakShortcut')})`) - } - } if (settings.get('resetBreaksShortcut') !== '') { const resetBreaksShortcut = globalShortcut.register(settings.get('resetBreaksShortcut'), () => { log.info('Stretchly: resetting breaks by shortcut') diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 59159d1f4..3ad89dc2e 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -8,7 +8,8 @@ const intervals = { pauseBreaksUntilMorningShortcut: null, pauseBreaksToggleShortcut: 1, // 1 means pause indefinitely skipToNextScheduledBreakShortcut: null, - skipToNextMiniBreakShortcut: null + skipToNextMiniBreakShortcut: null, + skipToNextLongBreakShortcut: null } function calculateInterval (name, settings) { @@ -43,6 +44,12 @@ function onShortcut ({ name, settings, log, breakPlanner, functions }) { return } + if (name === 'skipToNextLongBreakShortcut') { + log.info('Stretchly: skipping to next Long Break by shortcut') + functions.skipToBreak() + return + } + const interval = calculateInterval(name, settings) functions.pauseBreaks(interval) } diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 0e7c19d90..408bf040a 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -111,6 +111,26 @@ describe('pauseBreaksShortcut', () => { }) }) + describe('skipToNextLongBreakShortcut', () => { + it('skips to next scheduled long break', () => { + const log = { info: vi.fn() } + const skipToBreak = vi.fn() + const pauseBreaks = vi.fn() + + onShortcut({ + name: 'skipToNextLongBreakShortcut', + settings: null, + breakPlanner: null, + functions: { skipToBreak, pauseBreaks }, + log + }) + + expect(log.info).toHaveBeenCalledWith('Stretchly: skipping to next Long Break by shortcut') + expect(skipToBreak).toHaveBeenCalled() + expect(pauseBreaks).not.toHaveBeenCalled() + }) + }) + describe('skipToNextMiniBreakShortcut', () => { it('skips to next scheduled microbreak', () => { const log = { info: vi.fn() } @@ -219,7 +239,8 @@ describe('pauseBreaksShortcut', () => { pauseBreaksUntilMorningShortcut: 4, pauseBreaksToggleShortcut: 5, skipToNextScheduledBreakShortcut: 6, - skipToNextMiniBreakShortcut: 7 + skipToNextMiniBreakShortcut: 7, + skipToNextLongBreakShortcut: 8 } const settings = { get: vi.fn((name) => intervals[name]) } @@ -235,18 +256,18 @@ describe('pauseBreaksShortcut', () => { // Check shortcut registration // ------------ - expect(globalShortcut.register).toHaveBeenCalledTimes(8) + expect(globalShortcut.register).toHaveBeenCalledTimes(9) - for (let i = 0; i < 8; i++) { + for (let i = 0; i < 9; i++) { expect(globalShortcut.register.mock.calls[i][0]).toBe(i) } // Check log // ------------ - expect(log.info).toHaveBeenCalledTimes(8) + expect(log.info).toHaveBeenCalledTimes(9) - for (let i = 0; i < 8; i++) { + for (let i = 0; i < 9; i++) { expect(log.info.mock.calls[i][0]).toMatch(`registration successful (${i})`) } }) From 8e144d86179070daba307e452465a4e70beb85a6 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:14:33 +1000 Subject: [PATCH 11/15] Move resetBreaksShortcut out of main.js --- app/main.js | 14 +------------- app/utils/pauseBreaksShortcut.js | 9 ++++++++- test/pauseBreaksShortcut.js | 31 ++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/app/main.js b/app/main.js index 7174931a5..7183ca63b 100644 --- a/app/main.js +++ b/app/main.js @@ -268,21 +268,9 @@ async function initialize (isAppStart = true) { log, globalShortcut, breakPlanner, - functions: { pauseBreaks, resumeBreaks, skipToBreak, skipToMicrobreak } + functions: { pauseBreaks, resumeBreaks, skipToBreak, skipToMicrobreak, resetBreaks } }) - if (settings.get('resetBreaksShortcut') !== '') { - const resetBreaksShortcut = globalShortcut.register(settings.get('resetBreaksShortcut'), () => { - log.info('Stretchly: resetting breaks by shortcut') - resetBreaks() - }) - - if (!resetBreaksShortcut) { - log.warn('Stretchly: resetBreaksShortcut registration failed') - } else { - log.info(`Stretchly: resetBreaksShortcut registration successful (${settings.get('resetBreaksShortcut')})`) - } - } loadIdeas() updateTray() } diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 3ad89dc2e..9c4aa385a 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -9,7 +9,8 @@ const intervals = { pauseBreaksToggleShortcut: 1, // 1 means pause indefinitely skipToNextScheduledBreakShortcut: null, skipToNextMiniBreakShortcut: null, - skipToNextLongBreakShortcut: null + skipToNextLongBreakShortcut: null, + resetBreaksShortcut: null } function calculateInterval (name, settings) { @@ -50,6 +51,12 @@ function onShortcut ({ name, settings, log, breakPlanner, functions }) { return } + if (name === 'resetBreaksShortcut') { + log.info('Stretchly: resetting breaks by shortcut') + functions.resetBreaks() + return + } + const interval = calculateInterval(name, settings) functions.pauseBreaks(interval) } diff --git a/test/pauseBreaksShortcut.js b/test/pauseBreaksShortcut.js index 408bf040a..daf82d47b 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/pauseBreaksShortcut.js @@ -111,6 +111,26 @@ describe('pauseBreaksShortcut', () => { }) }) + describe('resetBreaksShortcut', () => { + it('rest breaks', () => { + const log = { info: vi.fn() } + const resetBreaks = vi.fn() + const pauseBreaks = vi.fn() + + onShortcut({ + name: 'resetBreaksShortcut', + settings: null, + breakPlanner: null, + functions: { resetBreaks, pauseBreaks }, + log + }) + + expect(log.info).toHaveBeenCalledWith('Stretchly: resetting breaks by shortcut') + expect(resetBreaks).toHaveBeenCalled() + expect(pauseBreaks).not.toHaveBeenCalled() + }) + }) + describe('skipToNextLongBreakShortcut', () => { it('skips to next scheduled long break', () => { const log = { info: vi.fn() } @@ -240,7 +260,8 @@ describe('pauseBreaksShortcut', () => { pauseBreaksToggleShortcut: 5, skipToNextScheduledBreakShortcut: 6, skipToNextMiniBreakShortcut: 7, - skipToNextLongBreakShortcut: 8 + skipToNextLongBreakShortcut: 8, + resetBreaksShortcut: 9 } const settings = { get: vi.fn((name) => intervals[name]) } @@ -256,18 +277,18 @@ describe('pauseBreaksShortcut', () => { // Check shortcut registration // ------------ - expect(globalShortcut.register).toHaveBeenCalledTimes(9) + expect(globalShortcut.register).toHaveBeenCalledTimes(10) - for (let i = 0; i < 9; i++) { + for (let i = 0; i < 10; i++) { expect(globalShortcut.register.mock.calls[i][0]).toBe(i) } // Check log // ------------ - expect(log.info).toHaveBeenCalledTimes(9) + expect(log.info).toHaveBeenCalledTimes(10) - for (let i = 0; i < 9; i++) { + for (let i = 0; i < 10; i++) { expect(log.info.mock.calls[i][0]).toMatch(`registration successful (${i})`) } }) From 227f8a4ed73f92db7ae00a7ff3bb58563ba8d8bd Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:23:27 +1000 Subject: [PATCH 12/15] Refactor --- app/utils/pauseBreaksShortcut.js | 65 +++++++++++++++----------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 9c4aa385a..8d5ec304e 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -22,43 +22,40 @@ function calculateInterval (name, settings) { } function onShortcut ({ name, settings, log, breakPlanner, functions }) { - if (name === 'pauseBreaksToggleShortcut' && breakPlanner.isPaused) { - functions.resumeBreaks(false) - return - } - - if (name === 'skipToNextScheduledBreakShortcut') { - log.info('Stretchly: skipping to next scheduled Break by shortcut') - - if (breakPlanner._scheduledBreakType === 'break') { - functions.skipToBreak() - } else if (breakPlanner._scheduledBreakType === 'microbreak') { + switch (name) { + case 'pauseBreaksToggleShortcut': + if (breakPlanner.isPaused) { + functions.resumeBreaks(false) + } else { + functions.pauseBreaks(1) + } + break + case 'skipToNextScheduledBreakShortcut': + log.info('Stretchly: skipping to next scheduled Break by shortcut') + if (breakPlanner._scheduledBreakType === 'break') { + functions.skipToBreak() + } else if (breakPlanner._scheduledBreakType === 'microbreak') { + functions.skipToMicrobreak() + } + break + case 'skipToNextMiniBreakShortcut': + log.info('Stretchly: skipping to next Mini Break by shortcut') functions.skipToMicrobreak() + break; + case 'skipToNextLongBreakShortcut': + log.info('Stretchly: skipping to next Long Break by shortcut') + functions.skipToBreak() + break + case 'resetBreaksShortcut': + log.info('Stretchly: resetting breaks by shortcut') + functions.resetBreaks() + break + default: { + const interval = calculateInterval(name, settings) + functions.pauseBreaks(interval) + break } - - return } - - if (name === 'skipToNextMiniBreakShortcut') { - log.info('Stretchly: skipping to next Mini Break by shortcut') - functions.skipToMicrobreak() - return - } - - if (name === 'skipToNextLongBreakShortcut') { - log.info('Stretchly: skipping to next Long Break by shortcut') - functions.skipToBreak() - return - } - - if (name === 'resetBreaksShortcut') { - log.info('Stretchly: resetting breaks by shortcut') - functions.resetBreaks() - return - } - - const interval = calculateInterval(name, settings) - functions.pauseBreaks(interval) } function setupBreak ({ name, shortcutText, settings, log, globalShortcut, breakPlanner, functions }) { From cbbb4fe156075bf9b18472310f60a9f28549ad16 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:23:37 +1000 Subject: [PATCH 13/15] Refactor --- app/utils/pauseBreaksShortcut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/pauseBreaksShortcut.js index 8d5ec304e..1a811faf6 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/pauseBreaksShortcut.js @@ -41,7 +41,7 @@ function onShortcut ({ name, settings, log, breakPlanner, functions }) { case 'skipToNextMiniBreakShortcut': log.info('Stretchly: skipping to next Mini Break by shortcut') functions.skipToMicrobreak() - break; + break case 'skipToNextLongBreakShortcut': log.info('Stretchly: skipping to next Long Break by shortcut') functions.skipToBreak() From ffd88e63d3b2237e760c9d44d56e676643842108 Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:31:33 +1000 Subject: [PATCH 14/15] Rename break shortcuts files for clarity --- app/main.js | 4 ++-- .../{pauseBreaksShortcut.js => breakShortcuts.js} | 12 +++++++----- test/{pauseBreaksShortcut.js => breakShortcuts.js} | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) rename app/utils/{pauseBreaksShortcut.js => breakShortcuts.js} (88%) rename test/{pauseBreaksShortcut.js => breakShortcuts.js} (97%) diff --git a/app/main.js b/app/main.js index 7183ca63b..6ef4c197a 100644 --- a/app/main.js +++ b/app/main.js @@ -8,7 +8,7 @@ const i18next = require('i18next') const Backend = require('i18next-fs-backend') const log = require('electron-log/main') const Store = require('electron-store') -const { registerPauseBreaksShortcuts } = require('./utils/pauseBreaksShortcut') +const { registerBreakShortcuts } = require('./utils/breakShortcuts') process.on('uncaughtException', (err, _) => { log.error(err) @@ -263,7 +263,7 @@ async function initialize (isAppStart = true) { } globalShortcut.unregisterAll() - registerPauseBreaksShortcuts({ + registerBreakShortcuts({ settings, log, globalShortcut, diff --git a/app/utils/pauseBreaksShortcut.js b/app/utils/breakShortcuts.js similarity index 88% rename from app/utils/pauseBreaksShortcut.js rename to app/utils/breakShortcuts.js index 1a811faf6..394266443 100644 --- a/app/utils/pauseBreaksShortcut.js +++ b/app/utils/breakShortcuts.js @@ -1,6 +1,8 @@ const { UntilMorning } = require('./untilMorning') -const intervals = { +// Keys are the names of shortcuts in the settings, +// values are break pause intervals in milliseconds (or null if not applicable) +const shortcuts = { pauseBreaksFor30MinutesShortcut: 30 * 60 * 1000, pauseBreaksFor1HourShortcut: 3600 * 1000, pauseBreaksFor2HoursShortcut: 2 * 3600 * 1000, @@ -18,7 +20,7 @@ function calculateInterval (name, settings) { return new UntilMorning(settings).msToSunrise() } - return intervals[name] + return shortcuts[name] } function onShortcut ({ name, settings, log, breakPlanner, functions }) { @@ -68,8 +70,8 @@ function setupBreak ({ name, shortcutText, settings, log, globalShortcut, breakP } } -function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, breakPlanner, functions }) { - for (const name of Object.keys(intervals)) { +function registerBreakShortcuts ({ settings, log, globalShortcut, breakPlanner, functions }) { + for (const name of Object.keys(shortcuts)) { const shortcutText = settings.get(name) if (shortcutText === '') continue @@ -88,6 +90,6 @@ function registerPauseBreaksShortcuts ({ settings, log, globalShortcut, breakPla module.exports = { calculateInterval, onShortcut, - registerPauseBreaksShortcuts, + registerBreakShortcuts, setupBreak } diff --git a/test/pauseBreaksShortcut.js b/test/breakShortcuts.js similarity index 97% rename from test/pauseBreaksShortcut.js rename to test/breakShortcuts.js index daf82d47b..e9d217e7d 100644 --- a/test/pauseBreaksShortcut.js +++ b/test/breakShortcuts.js @@ -1,6 +1,6 @@ import { vi } from 'vitest' import { expect } from 'chai' -import { calculateInterval, registerPauseBreaksShortcuts, setupBreak, onShortcut } from '../app/utils/pauseBreaksShortcut' +import { calculateInterval, registerBreakShortcuts, setupBreak, onShortcut } from '../app/utils/breakShortcuts' describe('pauseBreaksShortcut', () => { describe('calculateInterval', () => { @@ -245,7 +245,7 @@ describe('pauseBreaksShortcut', () => { }) }) - describe('registerPauseBreaksShortcuts', () => { + describe('registerBreakShortcuts', () => { it('should register all shortcuts from settings', () => { const globalShortcut = { register: vi.fn().mockReturnValue(true) } const log = { info: vi.fn(), warn: vi.fn() } @@ -266,7 +266,7 @@ describe('pauseBreaksShortcut', () => { const settings = { get: vi.fn((name) => intervals[name]) } - registerPauseBreaksShortcuts({ + registerBreakShortcuts({ settings, log, globalShortcut, @@ -300,7 +300,7 @@ describe('pauseBreaksShortcut', () => { const settings = { get: vi.fn((name) => name === 'pauseBreaksFor30MinutesShortcut' ? 'key' : '') } - registerPauseBreaksShortcuts({ + registerBreakShortcuts({ settings, log, globalShortcut, From 0102f91458107332e43ea78dd3ecbfc94165955e Mon Sep 17 00:00:00 2001 From: Evgenii Neumerzhitckii Date: Thu, 25 Jul 2024 13:51:32 +1000 Subject: [PATCH 15/15] Fix empty menu accelerator warning The warning "doesn't contain a valid key" was shown in console logs when pause break shortcut was empty. The warning only appread in Linux but not in Windows or Mac. --- app/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/main.js b/app/main.js index 6ef4c197a..f42cfe829 100644 --- a/app/main.js +++ b/app/main.js @@ -1258,31 +1258,31 @@ function getTrayMenuTemplate () { submenu: [ { label: i18next.t('utils.minutes', { count: 30 }), - accelerator: settings.get('pauseBreaksFor30MinutesShortcut'), + accelerator: settings.get('pauseBreaksFor30MinutesShortcut') || null, click: function () { pauseBreaks(1800 * 1000) } }, { label: i18next.t('main.forHour'), - accelerator: settings.get('pauseBreaksFor1HourShortcut'), + accelerator: settings.get('pauseBreaksFor1HourShortcut') || null, click: function () { pauseBreaks(3600 * 1000) } }, { label: i18next.t('main.for2Hours'), - accelerator: settings.get('pauseBreaksFor2HoursShortcut'), + accelerator: settings.get('pauseBreaksFor2HoursShortcut') || null, click: function () { pauseBreaks(3600 * 2 * 1000) } }, { label: i18next.t('main.for5Hours'), - accelerator: settings.get('pauseBreaksFor5HoursShortcut'), + accelerator: settings.get('pauseBreaksFor5HoursShortcut') || null, click: function () { pauseBreaks(3600 * 5 * 1000) } }, { label: i18next.t('main.untilMorning'), - accelerator: settings.get('pauseBreaksUntilMorningShortcut'), + accelerator: settings.get('pauseBreaksUntilMorningShortcut') || null, click: function () { const untilMorning = new UntilMorning(settings).msToSunrise() pauseBreaks(untilMorning)