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

Allow the next break or microbreak to be scheduled from the CLI #1092

Merged
merged 4 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added
- advanced option for app exclusion check interval
- support Apple silicon
- build for Apple silicon
- ability to schedule break from command line

## [1.9.0] - 2021-12-24
### Changed
Expand Down
10 changes: 5 additions & 5 deletions app/breaksPlanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,30 +168,30 @@ class BreaksPlanner extends EventEmitter {
this.emit('updateToolTip')
}

skipToMicrobreak () {
skipToMicrobreak (delay = 100) {
this.scheduler.cancel()
const shouldBreak = this.settings.get('break')
const shouldMicrobreak = this.settings.get('microbreak')
const breakInterval = this.settings.get('breakInterval') + 1
if (shouldBreak && shouldMicrobreak) {
const breakInterval = this.settings.get('breakInterval') + 1
hovancik marked this conversation as resolved.
Show resolved Hide resolved
if (this.breakNumber % breakInterval === 0) {
this.breakNumber = 1
}
}
this.scheduler = new Scheduler(() => this.emit('startMicrobreak'), 100, 'startMicrobreak')
this.scheduler = new Scheduler(() => this.emit('startMicrobreak'), delay, 'startMicrobreak')
this.scheduler.plan()
this.emit('updateToolTip')
}

skipToBreak () {
skipToBreak (delay = 100) {
this.scheduler.cancel()
const shouldBreak = this.settings.get('break')
const shouldMicrobreak = this.settings.get('microbreak')
if (shouldBreak && shouldMicrobreak) {
const breakInterval = this.settings.get('breakInterval') + 1
this.breakNumber = breakInterval
}
this.scheduler = new Scheduler(() => this.emit('startBreak'), 100, 'startBreak')
this.scheduler = new Scheduler(() => this.emit('startBreak'), delay, 'startBreak')
this.scheduler.plan()
this.emit('updateToolTip')
}
Expand Down
63 changes: 43 additions & 20 deletions app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,26 +85,39 @@ if (!gotTheLock) {
}

if (!cmd.checkInMain()) {
log.info(`Stretchly: command '${cmd.command}' executed in second-instance, dropped in main instance`)
log.info(`Stretchly: command '${cmd.command}' executed in second instance, dropped in main instance`)
return
}

switch (cmd.command) {
case 'reset':
log.info('Stretchly: reseting breaks (requested by second instance)')
log.info('Stretchly: resetting breaks (requested by second instance)')
resetBreaks()
break

case 'mini':
case 'mini': {
log.info('Stretchly: skip to Mini Break (requested by second instance)')
const delay = cmd.waitToMs()
if (delay === -1) {
log.error('Stretchly: error parsing wait interval to ms because of invalid value')
return
}
if (cmd.options.title) nextIdea = [cmd.options.title]
if (!cmd.options.noskip) skipToMicrobreak()
if (!cmd.options.noskip || delay) skipToMicrobreak(delay)
break
}

case 'long':
case 'long': {
log.info('Stretchly: skip to Long Break (requested by second instance)')
const delay = cmd.waitToMs()
if (delay === -1) {
log.error('Stretchly: error parsing wait interval to ms because of invalid value')
return
}
nextIdea = [cmd.options.title ? cmd.options.title : null, cmd.options.text ? cmd.options.text : null]
if (!cmd.options.noskip) skipToBreak()
if (!cmd.options.noskip || delay) skipToBreak(delay)
break
}

case 'resume':
log.info('Stretchly: resume Breaks (requested by second instance)')
Expand All @@ -119,13 +132,13 @@ if (!gotTheLock) {

case 'pause': {
log.info('Stretchly: pause Breaks (requested by second instance)')
const ms = cmd.durationToMs(settings)
const duration = cmd.durationToMs(settings)
// -1 indicates an invalid value
if (ms === -1) {
log.error('Stretchly: error when parsing duration to ms because of unvalid value')
if (duration === -1) {
log.error('Stretchly: error when parsing duration to ms because of invalid value')
return
}
pauseBreaks(ms)
pauseBreaks(duration)
break
}
}
Expand Down Expand Up @@ -223,7 +236,7 @@ function initialize (isAppStart = true) {
if (!resumeBreaksShortcut) {
log.warn('Stretchly: resumeBreaksShortcut registration failed')
} else {
log.info(`Stretchly: resumeBreaksShortcut registration succesful (${settings.get('resumeBreaksShortcut')})`)
log.info(`Stretchly: resumeBreaksShortcut registration successful (${settings.get('resumeBreaksShortcut')})`)
}
}
if (settings.get('pauseBreaksShortcut') !== '') {
Expand All @@ -234,7 +247,7 @@ function initialize (isAppStart = true) {
if (!pauseBreaksShortcut) {
log.warn('Stretchly: pauseBreaksShortcut registration failed')
} else {
log.info(`Stretchly: pauseBreaksShortcut registration succesful (${settings.get('pauseBreaksShortcut')})`)
log.info(`Stretchly: pauseBreaksShortcut registration successful (${settings.get('pauseBreaksShortcut')})`)
}
}
}
Expand Down Expand Up @@ -942,27 +955,37 @@ function postponeBreak (shouldPlaySound = false) {
updateTray()
}

function skipToMicrobreak () {
function skipToMicrobreak (delay) {
if (microbreakWins) {
microbreakWins = breakComplete(false, microbreakWins)
}
if (breakWins) {
breakWins = breakComplete(false, breakWins)
}
breakPlanner.skipToMicrobreak()
log.info('Stretchly: skipping to Mini Break')
if (delay) {
breakPlanner.skipToMicrobreak(delay)
log.info(`Stretchly: skipping to Mini Break in ${delay}ms`)
} else {
breakPlanner.skipToMicrobreak()
log.info('Stretchly: skipping to Mini Break')
}
updateTray()
}

function skipToBreak () {
function skipToBreak (delay) {
if (microbreakWins) {
microbreakWins = breakComplete(false, microbreakWins)
}
if (breakWins) {
breakWins = breakComplete(false, breakWins)
}
breakPlanner.skipToBreak()
log.info('Stretchly: skipping to Long Break')
if (delay) {
breakPlanner.skipToBreak(delay)
log.info(`Stretchly: skipping to Long Break in ${delay}ms`)
} else {
breakPlanner.skipToBreak()
log.info('Stretchly: skipping to Long Break')
}
updateTray()
}

Expand All @@ -974,7 +997,7 @@ function resetBreaks () {
breakWins = breakComplete(false, breakWins)
}
breakPlanner.reset()
log.info('Stretchly: reseting breaks')
log.info('Stretchly: resetting breaks')
updateTray()
}

Expand Down Expand Up @@ -1004,7 +1027,7 @@ function pauseBreaks (milliseconds) {
finishBreak(false)
}
breakPlanner.pause(milliseconds)
log.info(`Stretchly: pausing breaks for ${milliseconds}`)
log.info(`Stretchly: pausing breaks for ${milliseconds}ms`)
updateTray()
}

Expand Down
1 change: 0 additions & 1 deletion app/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const log = require('electron-log')
const path = require('path')
log.transports.file.resolvePath = () => path.join(remote.app.getPath('userData'), 'logs/main.log')


window.onload = (e) => {
ipcRenderer.on('playSound', (event, file, volume) => {
const audio = new Audio(`audio/${file}.wav`)
Expand Down
26 changes: 22 additions & 4 deletions app/utils/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const allOptions = {
description: 'Do not skip directly to this break (Long or Mini)',
withValue: false
},
wait: {
lkrms marked this conversation as resolved.
Show resolved Hide resolved
long: '--wait',
short: '-w',
description: 'Specify an interval to wait before skipping to this break (Long or Mini) [HHhMMm|HHh|MMm|MM]',
withValue: true
},
duration: {
long: '--duration',
short: '-d',
Expand Down Expand Up @@ -50,11 +56,11 @@ const allCommands = {
},
mini: {
description: 'Skip to the Mini Break, customize it',
options: [allOptions.title, allOptions.noskip]
options: [allOptions.title, allOptions.noskip, allOptions.wait]
},
long: {
description: 'Skip to the Long Break, customize it',
options: [allOptions.text, allOptions.title, allOptions.noskip]
options: [allOptions.text, allOptions.title, allOptions.noskip, allOptions.wait]
}
}

Expand Down Expand Up @@ -85,6 +91,10 @@ const allExamples = [{
{
cmd: 'stretchly long -T "Stretch up!" -t "Go stretch!"',
description: 'Start a long break, with the title "Stretch up!" and text "Go stretch!"'
},
{
cmd: 'stretchly long -w 20m -T "Stretch up!"',
description: 'Wait 20 minutes, then start a long break with the title set to "Stretch up!"'
}]

// Parse cmd line, check if valid and put variables in a dedicated object
Expand Down Expand Up @@ -145,7 +155,7 @@ class Command {
})

if (!valid) {
log.error(`Stretchly ${this.isFirstInstance ? '' : '2'}: options '${name}' is not valid for command '${this.command}'`)
log.error(`Stretchly${this.isFirstInstance ? '' : ' 2'}: option '${name}' is not valid for command '${this.command}'`)
}
}

Expand All @@ -164,7 +174,7 @@ class Command {

default:
if (this.hasSupportedCommand) {
log.info(`Stretchly ${this.isFirstInstance ? '' : '2'}: forwarding command '${this.command}' to the main instance`)
log.info(`Stretchly${this.isFirstInstance ? '' : ' 2'}: forwarding command '${this.command}' to the main instance`)
}
}
}
Expand All @@ -186,6 +196,14 @@ class Command {
}
}

waitToMs () {
if (!this.options.wait) {
return 0
}

return parseDuration(this.options.wait)
}

checkInMain () {
if (!this.command) {
return false
Expand Down
66 changes: 66 additions & 0 deletions test/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,70 @@ describe('commands', () => {
const cmd = new Command(input, '1.2.3')
cmd.durationToMs(null).should.be.equal(-1)
})

it('parses a number scheduler as the number of minutes to break', () => {
const input = ['long', '-w', '60']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(60 * 60 * 1000)
})

it('parses a scheduler argument with hours and minutes', () => {
const input = ['long', '-w', '4h39m']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(4 * 60 * 60 * 1000 + 39 * 60 * 1000)
})

it('parses a scheduler argument with hours and minutes in the upper case', () => {
const input = ['long', '-w', '4H39M']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(4 * 60 * 60 * 1000 + 39 * 60 * 1000)
})

it('parses a scheduler argument with just the minutes', () => {
const input = ['long', '-w', '60m']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(60 * 60 * 1000)
})

it('parses a scheduler argument with just the hours', () => {
const input = ['long', '-w', '184h']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(184 * 60 * 60 * 1000)
})

it('returns -1 if there\'s extra text in the scheduler argument', () => {
new Command(['long', '-w', 'foo4h39mbar'], '1.2.3').waitToMs(null).should.be.equal(-1)
new Command(['long', '-w', 'foo4h39m'], '1.2.3').waitToMs(null).should.be.equal(-1)
new Command(['long', '-w', '4h39mbar'], '1.2.3').waitToMs(null).should.be.equal(-1)
})

it('returns -1 if a number scheduler argument is zero', () => {
const input = ['long', '-w', '0']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(-1)
})

it('returns -1 if the scheduler argument with the hours and minutes evaluates to zero', () => {
const input = ['long', '-w', '0h0m']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(-1)
})

it('returns -1 if the scheduler argument with just the minutes evaluates to zero', () => {
const input = ['long', '-w', '0m']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(-1)
})

it('returns -1 if the scheduler argument with just the hours evaluates to zero', () => {
const input = ['long', '-w', '0h']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(-1)
})

it('should return -1 if the scheduler argument is not in a known format', () => {
const input = ['long', '-w', '10i20k']
const cmd = new Command(input, '1.2.3')
cmd.waitToMs(null).should.be.equal(-1)
})
})