Skip to content

Commit

Permalink
Allow the next break or microbreak to be scheduled from the CLI (#1092)
Browse files Browse the repository at this point in the history
Allow the next break or microbreak to be scheduled from the CLI

Co-authored-by: Jan Hovancik <[email protected]>
  • Loading branch information
lkrms and hovancik authored Feb 21, 2022
1 parent 9614c13 commit e180a08
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 31 deletions.
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
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: {
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)
})
})

0 comments on commit e180a08

Please sign in to comment.