Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/1457 add shorcuts for pause breaks #1468

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1315,26 +1317,31 @@ function getTrayMenuTemplate () {
submenu: [
{
label: i18next.t('utils.minutes', { count: 30 }),
accelerator: settings.get('pauseBreaksFor30MinutesShortcut'),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not that important but returns [18960:0723/192752.999383:WARNING:accelerator_util.cc(65)] doesn't contain a valid key when no value set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted. How do I reproduce this error? I tried to start the app (npm run start) with empty string "" values for the shortcuts but I don't see this error in the terminal.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try with npm run dev, it gives more debug info.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, the warning only appeared in Ubuntu for me but not in Windows or Mac.

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)
Expand Down
5 changes: 5 additions & 0 deletions app/utils/defaultSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ module.exports = {
appExclusionsCheckInterval: 1000,
pauseForSuspendOrLock: true,
pauseBreaksToggleShortcut: '',
pauseBreaksFor30MinutesShortcut: '',
pauseBreaksFor1HourShortcut: '',
pauseBreaksFor2HoursShortcut: '',
pauseBreaksFor5HoursShortcut: '',
pauseBreaksUntilMorningShortcut: '',
screen: 'primary',
timeToBreakInTray: false,
currentTimeInBreaks: false,
Expand Down
44 changes: 44 additions & 0 deletions app/utils/pauseBreaksShortcut.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const { UntilMorning } = require('./untilMorning')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please what do you think about registering pauseBreaksToggleShortcut? Haven't had time think myself, but it hits me we have one shortcut left in main.js regarding to pausing.

Or even put all shortcuts here? (like skipToNextScheduledBreakShortcut, skipToNextMiniBreakShortcut and such).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


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
}
73 changes: 73 additions & 0 deletions test/pauseBreaksShortcut.js
Original file line number Diff line number Diff line change
@@ -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)')
})
})
})
4 changes: 2 additions & 2 deletions test/untilMorning.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
Expand Down
Loading