Time Out icon Time Out
You deserve a break

Remember 'Break control' choice between breaks

I have created a new theme which selects a random exercise to perform during each break.

I have managed to ensure non-repetition of exercises through use of localStorage.

However, I would only like to move on to the next exercise if the current break expires and not if I choose to postpone it.

Is it possible to store the 'break control choice' in localStorage also or is there a facility to persist the choice between the breaks?

I'll be happy to share my code once I've nailed this.

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

That isn't an option at present, but it's definitely a good idea. I'd be happy to work with you on what you need. There are lots of break properties that could be provided to themes, but I haven't spent time implementing them until a need arises.

Re: Remember 'Break control' choice between breaks

Thanks for your response.

I'm approaching this from a front-end web background and so the ability to create custom themes using HTML/CSS/JS was a real selling point for me.

For my limited need I would only need to know if the break was:

- 'expired' or 'successfully run', so that I can mark the exercise as complete and queue up the next.
- 'postponed', so that I can leave the exercise in the queue.
- 'skipped', so that I can un-queue the exercise and queue up another.

For me it is much of a muchness whether I:

- Read the choice made for the previous break when the document loads from, for example, localStorage and front-load the queue management.
- Listen out for a break control choice event and perform the queue management at the endof the current break.

What are your thoughts?

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

I certainly welcome work on custom themes, and would love to include more in future versions.

As shown in the "Text" theme, Time Out has the ability (with "html5" type themes) to provide info about the break via this JavaScript call:

window.webkit.messageHandlers.getTimeOutInfo.postMessage('summary');

This results in a callback with a JSON parameter:

function timeOutInfo(json)
{
var obj = JSON.parse(json);

breakIdentifier = 'TimeOutText-' + obj.breakIdentifier;
...
}

(See the "Text" theme for the full example.)

This JSON currently includes the key/value pairs "format" (e.g. 1), "level" (e.g. "summary"), "appVersion" (e.g. "2.0"), "appRelease" (e.g. "2010"), "breakName" (e.g. "Normal"), and "breakIdentifier" (e.g. a UUID for the break).

So I could easily add additional properties to that JSON, e.g. a flag to indicate if the previous break was finished or deferred (postponed or skipped), and/or the dates when last deferred, done, started, and next due.

You could look in the break data file for the available properties, e.g. "~/Library/Group Containers/6Z7QW53WB6.com.dejal.timeout/Breaks/Normal.tobreak" (for the "Normal" break of the direct edition); the Time Out data is also JSON.

Another option could be for Time Out to send a JavaScript message to notify the theme when the break ends, either via finishing or being deferred (skipped or postponed). I'm not sure if there's a performance penalty for calling a JavaScript function (or for that matter what happens if it isn't implemented... presumably nothing). So I could add a theme Info.json property for whether or not to send that message. Or it could be requested from JavaScript via another callback, e.g.:

window.webkit.messageHandlers.getTimeOutState.postMessage('');

(I'm not sure what parameter would make sense there.)

Would one of those approaches work for you? Which would you prefer? Though I'm tempted to add both approaches.

Re: Remember 'Break control' choice between breaks

OK, nice... The pieces of the puzzle are starting to come together.

Forgive me for my ignorance but so far as I can see the argument for the `postMessage('')` method has no affect on what is returned. Am I correct? Is there any way I can request a single property e.g. "breakIdentifier" or "lastState" (when it's implemented)?

In your previous response you only mentioned "finished or deferred (postponed or skipped)". Can you distinguish between "skipped" and "postponed"? Sometimes I just want to skip a certain exercise but I don't want to remove it from the regime altogether. Additionally, it might be nice to know how many breaks have been postponed or skipped so that I can punish myself by compounding the exercises when I finally give in an do them; a history of sorts.

For the meantime, lets just go for the simplest option which, for me, would be to provide the previous outcome as a property of the JSON passed via the `timeOutInfo()` callback. From my POV this would simply require a read on load and no event listeners. Once I have the functionality in place to handle that then it would be easy to modify to use a listener.

The simplest I can think of atm is:

{
    "breakName": "Micro",
    "appRelease": "2025",
    ...
    "prevBreak": {
        "state": "skipped|deferred|finished",
        "datetime": "2016-09-29T11:12:00Z"
    }
}

If you want do stick anything else in here while you're there than that'd be great, it will certainly help to have it in place if I suddenly have an idea for further development.

Furthering the idea of a 'history', the cleanest solution might be for me to construct it in localStorage which would mean that I could flush it at will. I could simply push the 'prevBreak' property onto an array. I'll have a play once I've got something to work with and see what happens.

Currently my theme is extremely simple and so the initialisation delay is negligible. Moving the listeners might come in handy if a theme has to do more in setting up for the next break i.e. fetch assets or build content etc. I was considering expanding my idea of incorporate images or animations of more complicated animations and so this might provide a nice use case.

This is quite tricky to debug when working on as I have to keep outputting stringified objects to the page and previewing the break. Any suggestions for this? No worries if not.

Thanks again.

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

The only argument for getTimeOutInfo.postMessage() that is currently supported is 'summary'. I could add support for getting individual properties if it were needed.

Currently Time Out doesn't store whether the last break was skipped or postponed. It does know that internally, but I didn't need to know that when loading the data, so it isn't stored. I could change that, though.

The current break state properties that are stored are:

  • enabled: boolean of whether or not the break is enabled
  • lastStarted: date/time the break was last started
  • lastDone: date/time the break was last successfully finished
  • lastDeferred: date/time the break was last skipped or postponed
  • pausedUntil: date/time the break will resume from a pause
  • nextDue: date/time the break is next due

Including the state info in the getTimeOutInfo JSON callback is probably reasonable.

Time Out doesn't store a history of previous breaks, yet. So I can't offer that for now. This is actually something I plan to add in a future version (maybe even 2.2), along with a log or graphical display of breaks taken, skipped, postponed, etc. I haven't figured out the best way to present that yet, but I have some ideas.

Re debugging, for simple themes I just display them in a Coda preview (my HTML editor of choice). Or a web browser. For a theme that interacts with Time Out like the "Text" one, editing it in place in the Themes folder and using a global keyboard shortcut to manually start the break is easy enough.

Re: Remember 'Break control' choice between breaks

I've got a similar workaround for debugging using a sublime build-system.

Access to all of the state info (lastStarted, lastDone, lastDeferred etc.) would be useful to me me in the future maybe. If it's easy to dump them into the getTimeOutInfo JSON then do so, or maybe it would be cleaner to attain them via getTimeOutInfo.postMessage('state')? Your call.

The difference between postponing and skipping is relatively key for me as it defines whether I want to unqueue the exercise altogether or ensure that it is redelivered. Assuming that you are going to make the break state info (see previous paragraph) available somehow, would a

{
    ...
    lastChoice: done|skipped|postponed
}

be possible? With it I could then interrogate the specific details rather than having to comparing the various times in order to work out what is going on.

Don't worry about the history for me, I suspect that my implementation will be vastly inferior to yours so I'll leave you to it. For now I will just build one in localStorage if i get that far.

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

I'm currently leaning towards including all properties in getTimeOutInfo.postMessage('summary'), but also having 'config' and 'state' parameters to get the current info and the state info, respectively. And maybe even the ability to ask for individual properties, e.g. 'breakIdentifier', though that might be making it too complex.

I will also add a property for the last choice, too.

I think we have a plan.

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

Alrighty. I've put together an alpha build with changes for this.

You can download it here.

You can also download a theme to test it from the Time Out Extras page (the Test theme at the top).

I ended up with something a bit different than the above.

I extended the break theme JavaScript to support a window.webkit.messageHandlers.getTimeOutState.postMessage('') message, to get a JSON of the break state information. The callback is timeOutState(json).

Properties include format (e.g. 1), nextDue (e.g. an ISO date like "2016-09-29T23:27:51Z"), lastStarted, lastDone, lastDeferred (also dates), lastPhase (e.g. done, skipped, or postponed), and currentPhase (e.g. pending, starting, started, or finishing).

lastPhase is what you'll want, but the others might be useful too.

While I was at it, I also extended the JavaScript to support a window.webkit.messageHandlers.getTimeOutConfig.postMessage('') message to get a JSON of the break configuration. The callback is timeOutConfig(json).

Properties include format (the JSON format, initially 1), identifier (the break's unique identifier), name (the break's name), durationSeconds (the break duration expressed in seconds), durationString (e.g. "10 minutes"), frequencySeconds (the frequency in seconds), frequencyString (e.g. "1 hour"), beginningSeconds (the fade-in time), endingSeconds (the fade-out time).

Let me know if you'd like any other properties for these, or if you find any issues.

Re: Remember 'Break control' choice between breaks

Amazing. I'm not being notified of your replies so apologies for the late response.

It's 04:40 my time so I'll have a crack at this ASAP and get back to you.

Thanks a lot David.

David Sinclair's picture

Re: Remember 'Break control' choice between breaks

Yeah, my forum CMS doesn't support emailing notifications. You can follow @SimonBot on Twitter to see when the forum changes.