taskell icon indicating copy to clipboard operation
taskell copied to clipboard

Pomodoro Timer For Tasks

Open KTSCode opened this issue 6 years ago • 14 comments

I know this is probably a pretty big ask, but I would love a CLI replacement for https://kanbanflow.com Taskell does everything that I want except integrate and track pomodors for tasks.

Ideal functionality would be:

  • hitting t while a task is highlighted starts a 25-minute countdown timer
    • should be located near task title or at the bottom or top of the screen
    • red font from 25:00 to 00:00
  • hitting s while a timer is going should stop and cancel it
  • when the timer reaches 0 it should change to 5:00
    • font should be green
  • hitting t while a 5:00 is on the clock should start the 5-minute break timer
  • once a timer is completed it should insert/increment a counter labeled pomodoro
    • ex: Task Title(pom: 1)

KTSCode avatar Apr 30 '19 23:04 KTSCode

I'll have a think about it. I don't imagine I'll have time to add it anytime soon, but don't want to rule it out.

smallhadroncollider avatar May 01 '19 11:05 smallhadroncollider

Hi @smallhadroncollider , I was looking for the same functionality, given that I use taskell to organize all my projects, and I generally do kanban and pomodoro on each. I could probably add it in myself (your implementation is very, very clean!), but would this feature be something you'd accept? I was thinking that it'd be nice to add it in a way where one would set up shell commands for notifications, similar to how eg. calcurse does it 2019-07-09-105743_703x103_scrot rather than the way described by OP.

In the absence of such feature, I've set up myself with a tiny shell script that uses dunst and process sleeping to achieve basic pomodoro notifications.

machinedgod avatar Jul 09 '19 14:07 machinedgod

I would definitely accept a pull-request that added the functionality and the shell command version looks interesting. I would maybe try getting it working roughly the way @KTSCode suggested first and then adding the command functionality as a separate request.

The tricky part is getting the time bit working, as timing requires a clock, which requires IO, which immediately makes it quite complicated to do in Haskell. It can be done in Brick by setting up a new channel and then adding a custom event handler for it. A basic example can be found here: https://github.com/smallhadroncollider/ascii-runner/blob/master/src/Game.hs. I guess you'd probably want to store some sort of clock in State and then work out time remaining from that? Although I've not given it much thought, so there may be a better way.

smallhadroncollider avatar Jul 09 '19 15:07 smallhadroncollider

I haven't really looked at how yet; for the beginning, I was curious if this would go against core idea of what Taskell is accomplishing - I'm a True Believer (c) in Unix philosophy ;-) Now that you've clarified that you'd accept PR, I'll go spend some time looking at how I'd do it, and then come back here with a bit more concrete plan, so we can agree on the how, before doing anything.

machinedgod avatar Jul 09 '19 16:07 machinedgod

So, after looking at it for a bit, for the first implementation, I would:

  1. As you suggested, add a custom event, just like Tick in the example you linked
  2. Open another thread solely to push Time events into the Brick (I assume there's a way to do this atomically)
  3. Store the task currently being tracked into the state, as a Maybe Pointer
  4. Store the Time when t key is hit (PomodoroTimerStart event)
  5. Update the draw to draw the (pseudo) format "mm:ss" (event time - state time)
  6. Whenever the Time event comes through, redraw (I assume its automatic, but just the timer portion)

If it works, probably the first next upgrade should be to fork and join the time update thread at will. Does this plan sound good to you? If not, what would you like me to do differently?

P.S. Unrelated - right now the bindings between actions and keys is 1:1. It would probably be useful to add some sort of context to the mix, so that same letter can trigger different actions.

machinedgod avatar Jul 09 '19 20:07 machinedgod

I'm not sure I really have a taskell philosophy to be honest: if it seems useful and doesn't change the basic idea then I'll probably consider it.

I'd probably just create a tick that's once a second and have it going constantly, updating a time property in State. This could then be used for due dates (and other time based features in the future). I can't imagine it would have much of an effect on performance.

Presumably you'd only want a pomdoro timer for one task at once? (I know nothing about Pomdoro, other than something about tomatoes - @KTSCode) If so then the Maybe Pointer solution sounds best, otherwise it would need to be part of the Task object.

Key to action bindings aren't 1:1. You can have multiple keys for the same action. There is also a context called mode in State, which will run different key bindings depending on what's happening (e.g. main view, task detail view, search mode). It gets nice and complicated (and could probably do with tidying up): https://github.com/smallhadroncollider/taskell/blob/master/src/Events/State/Types/Mode.hs

smallhadroncollider avatar Jul 11 '19 15:07 smallhadroncollider

@smallhadroncollider this is not particularly relevant to the underlying implementation for this feature but it does convey the idea behind it and may help inform the ergonomics https://youtu.be/mNBmG24djoY

@machinedgod thanks for taking interest in adding this feature!

KTSCode avatar Jul 17 '19 22:07 KTSCode

5/6 there.

Done:

  • Pomodoro types, states, actions and events
  • time pulses
  • rendering
  • tying it all up
  • polishing/refactoring the code

To go:

  • count pomodoros on tasks

machinedgod avatar Jul 18 '19 13:07 machinedgod

I'm sorry if you already considered this, but I didn't see it in the comments. Having the timer running with the process would force the user to keep taskell instance always running? If that so, I believe this could be a problem, I think I'm not the only one who open taskell only when needed and keep it close otherwise. A different approach I used in some pomodoro timer I implemented, is to save the start time of the pomodoro in the filesystem (usually in a file) and parse this file when taskell is running again.

clobrano avatar Nov 18 '19 08:11 clobrano

@clobrano Hmm, yes, that would be a different way of doing things.

I honestly don't have a strong opinion either way: I don't use pomodoro myself, so I don't really know the use cases.

I tend to keep Taskell open in a separate Tmux window, so the initially suggested version would work well with that, but I can see it might cause issues if you close Taskell in between.

I suppose there's no reason it couldn't store the timer info between sessions. I feel like that could be added later, the UI would still be the same?

smallhadroncollider avatar Nov 18 '19 11:11 smallhadroncollider

I honestly don't have a strong opinion either way: I don't use pomodoro myself, so I don't really know the use cases.

I use it just sometimes myself, for this I rely on an external tools just for this, for which simply exporting (e.g. copy to clipboard) the task description would be enough, but since I had this problem in the past, I thought it would be good to give this advice.

I suppose there's no reason it couldn't store the timer info between sessions. I feel like that could be added later, the UI would still be the same?

I believe so, yes.

clobrano avatar Nov 18 '19 15:11 clobrano

@clobrano If you store the current Pomodoro time in a file in order to close the app then there is no way for the application to notify you when the time is complete without some kind of background daemon, which is way outside the scope of this feature request. I think it's perfectly reasonable to require that the app be kept open in order for a timer feature to be used.

KTSCode avatar Nov 18 '19 16:11 KTSCode

At redtimer I use at to schedule the notification as postponed job. I believe this is supported in OSX as well.

clobrano avatar Nov 19 '19 08:11 clobrano

I think for now we should just aim to get it working while Taskell is open. Once that's working we can maybe look at more advanced functionality if Taskell is quit.

It would certainly be nice if you happened to quit Taskell accidentally then it wouldn't forget the timer.

smallhadroncollider avatar Nov 19 '19 12:11 smallhadroncollider