getting-things-gnome / gtg

Getting Things GNOME! trunk
https://wiki.gnome.org/Apps/GTG
GNU General Public License v3.0
553 stars 166 forks source link

[RFC] Refurbishing Recurring/Repeating tasks #645

Open zeddo123 opened 3 years ago

zeddo123 commented 3 years ago

We have received many issues and in hindsight I took short sided decisions about recurring tasks. That's why I opening this issue so that we can discuss how we might proceed.

New features

For these features, we could use dateutil proposed by @jaesivsm and @diegogangl.

History and duplicate tasks

This issue was raised here #636. The best behavior (if we want to preserve the "history") would be that then the task is re-opened, the new tasks gets deleted and replaced by the old one. Otherwise, we just update the due date.

Changing the name

I don't even know why I first chose recurring tasks instead of repeating. That's why I'm proposing to change the naming. The only issue with this is that some users might have gotten used to it.

I had an unexpected busy and stressful week, so I couldn't discuss it on IRC or even label issues. Now hopefully I can.

jaesivsm commented 3 years ago

I haven't had time to touch what I started recently (busy week also) but I can open a draft PR with my work in progress.

I'm more of a backend guy than anything. So, unless there is some amazing designer hidden somewhere I want to underline that the recursion rule RFC (somewhere in there) is very (and I mean very) flexible. I don't think we will (at least not on the first draft) have a UI that'll enable every possible combination. I don't think it's needed also.

What we have :

What's easy to add

What'll be impossible

recursion start and duplication fix

For that part I'd take a rather different approach :

diegogangl commented 3 years ago

Changing the name

Yeah I think repeating would be easier to grasp

I don't think we will (at least not on the first draft) have a UI that'll enable every possible combination. I don't think it's needed also.

We don't need to support every combination, just the most common uses. I think the discourse guys called it "user driven design", the issues that were opened are the cases we should work to cover in the UI. The other crazy could be exposed in the Quick Add field.

recursion start and duplication fix

For that part I'd take a rather different approach :

drop task duplication entirely
status is now a property
    returns real status if not done or not recursion rule
    if task.closed_date and datetime.now() > task.next_occurence > task.closed_date => not done
rrule comes with it's own dtstart but :
    on the fly replace it with task start_date if available

By status you mean the repeat status (enabled) or the task status?

jaesivsm commented 3 years ago

By status you mean the repeat status (enabled) or the task status?

The task status. I would also propose dropping all properties but the recursion rule (or repeating) attached to the task. Recursion would be enabled if the rule isn't None, otherwise it wouldn't.

diegogangl commented 3 years ago

The task status

Not sure if this is what you mean but that's sort of what I did in the new core branch: https://github.com/getting-things-gnome/gtg/blob/new_core/GTG/core/tasks2.py#L78

I would also propose dropping all properties but the recursion rule (or repeating) attached to the task. Recursion would be enabled if the rule isn't None, otherwise it wouldn't.

Sounds like a good idea in principle, but depends on whether we can get structured info from that string (can't see it in the dateutils docs). We need to know the different options to show them in the UI

jaesivsm commented 3 years ago

I was thinking of something like that

class Task:
    [...]
    def __init__(self):
        [...]
        self._status = Status.ACTIVE
    [...]
    @property 
    def status(self):
        if self._status is not Status.DONE or not self.recursion_rule:
            return self._status
        if datetime.now() > task.next_occurence > task.closed_date:
            return Status.ACTIVE
        return self._status

where next_occurence is based on dateutil.rrule.rrule.after()

Sounds like a good idea in principle, but depends on whether we can get structured info from that string (can't see it in the dateutils docs). We need to know the different options to show them in the UI

rrule can be serialized as a string but is an object with :

I've started to write a wrapper to interact with it (take a look).

edit: copy paste fury

diegogangl commented 3 years ago

I'm not too keen on the property idea TBH. Imagine running that function (at least) once for every task. In a list with +1K tasks it would add some noticeable overhead. We could add a fourth status (Status.REPEATING). So we treat them differently when closing or re-opening.

That wrapper is exactly what I was thinking about :ok_hand:

jaesivsm commented 3 years ago

We could add a fourth status (Status.REPEATING). So we treat them differently when closing or re-opening.

That'd be complicated since then we couldn't have a DONE AND REPEATING task.

Imagine running that function (at least) once for every task.

I don't think it'll affect the perf that much (from what I saw, it's mostly gtk boiler plate codes that takes most of the lag time). Anyway, implementing a caching mechanism limited in time with some logic to avoid thundering herd over the code above would not be very complicated.

diegogangl commented 3 years ago

That'd be complicated since then we couldn't have a DONE AND REPEATING task.

For the closed pane? I was thinking in that case we could duplicate tasks when they are closed. When re-opening, look for a task with the same name set to repeating and don't re-open.

jaesivsm commented 3 years ago

status represent the actual status of a task like DONE, ACTIVE. When you had the repeating status to the mix it makes the whole logic fuzzy. I'm quite sure it's a technical choice to be regretted down the line (with filtering, displaying or anything) and we better keep things simple and straightforward.

On the case of duplication of the task :

Neui commented 3 years ago

... it can't be good on space complexity, especially with user who never deletes their done tasks.

There is a feature (enabled by default AFAIK) to delete done tasks after 30 days, look into the preferences.

diegogangl commented 3 years ago

I do agree that the duplicating solution isn't ideal, but it's the only way with our current model + treeview system. If you want to do things more nicely we can work them on the new core. I didn't port any of the repeating task code

zeddo123 commented 3 years ago

I've been playing a bit with dateutil and rrules, and I was able to decrease the amount of code that was used to deal with repeating tasks. You can have a look at what I've been playing around with here, although a lot could change depending on how we rewrite the core.