Skip to content

Commit 13e709d

Browse files
authored
Merge pull request #3423 from chmac/2751-drop-scheduled-dates
feat: Add option to discard Scheduled date on new recurring tasks
2 parents 5a66d58 + 4eb0790 commit 13e709d

File tree

8 files changed

+86
-7
lines changed

8 files changed

+86
-7
lines changed

docs/Getting Started/Recurring Tasks.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ Use this setting to control where the recurring task is inserted. The default is
5555
> [!released]
5656
> Control of the location (or order) of the new task was introduced in Tasks 3.8.0
5757
58+
### Drop scheduled dates
59+
60+
Use this setting to control whether the scheduled date should be removed from the next occurrence. The scheduled date is only removed the task also has another date.
61+
5862
### Recurring Tasks with Custom Statuses
5963

6064
> [!Warning]

src/Config/Settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export interface Settings {
7676
filenameAsScheduledDateFormat: string;
7777
filenameAsDateFolders: string[];
7878
recurrenceOnNextLine: boolean;
79+
dropScheduledDateOnRecurrence: boolean;
7980

8081
// The custom status states.
8182
statusSettings: StatusSettings;
@@ -110,6 +111,7 @@ const defaultSettings: Settings = {
110111
filenameAsScheduledDateFormat: '',
111112
filenameAsDateFolders: [],
112113
recurrenceOnNextLine: false,
114+
dropScheduledDateOnRecurrence: false,
113115
statusSettings: new StatusSettings(),
114116
features: Feature.settingsFlags,
115117
generalSettings: {

src/Config/SettingsTab.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,23 @@ export class SettingsTab extends PluginSettingTab {
376376
});
377377
});
378378

379+
new Setting(containerEl)
380+
.setName(i18n.t('settings.recurringTasks.dropScheduledDate.name'))
381+
.setDesc(
382+
SettingsTab.createFragmentWithHTML(
383+
i18n.t('settings.recurringTasks.dropScheduledDate.description') +
384+
'</br>' +
385+
this.seeTheDocumentation('https://publish.obsidian.md/tasks/Getting+Started/Recurring+Tasks'),
386+
),
387+
)
388+
.addToggle((toggle) => {
389+
const { dropScheduledDateOnRecurrence } = getSettings();
390+
toggle.setValue(dropScheduledDateOnRecurrence).onChange(async (value) => {
391+
updateSettings({ dropScheduledDateOnRecurrence: value });
392+
await this.plugin.saveSettings();
393+
});
394+
});
395+
379396
// ---------------------------------------------------------------------------
380397
new Setting(containerEl).setName(i18n.t('settings.autoSuggest.heading')).setHeading();
381398
// ---------------------------------------------------------------------------

src/Task/Occurrence.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ export class Occurrence {
8787
* If the occurrence has no reference date, an empty {@link Occurrence} will be returned.
8888
*
8989
* @param nextReferenceDate
90+
* @param dropScheduledDate - Optional boolean to drop the scheduled date from the next occurrence so long as a start or due date exists.
9091
*/
91-
public next(nextReferenceDate: Date): Occurrence {
92+
public next(nextReferenceDate: Date, dropScheduledDate: boolean = false): Occurrence {
9293
// Only if a reference date is given. A reference date will exist if at
9394
// least one of the other dates is set.
9495
if (this.referenceDate === null) {
@@ -99,10 +100,21 @@ export class Occurrence {
99100
});
100101
}
101102

103+
const hasStartDate = this.startDate !== null;
104+
const hasDueDate = this.dueDate !== null;
105+
const canDropScheduledDate = hasStartDate || hasDueDate;
106+
const shouldDropScheduledDate = dropScheduledDate && canDropScheduledDate;
107+
108+
const startDate = this.nextOccurrenceDate(this.startDate, nextReferenceDate);
109+
const scheduledDate = shouldDropScheduledDate
110+
? null
111+
: this.nextOccurrenceDate(this.scheduledDate, nextReferenceDate);
112+
const dueDate = this.nextOccurrenceDate(this.dueDate, nextReferenceDate);
113+
102114
return new Occurrence({
103-
startDate: this.nextOccurrenceDate(this.startDate, nextReferenceDate),
104-
scheduledDate: this.nextOccurrenceDate(this.scheduledDate, nextReferenceDate),
105-
dueDate: this.nextOccurrenceDate(this.dueDate, nextReferenceDate),
115+
startDate,
116+
scheduledDate,
117+
dueDate,
106118
});
107119
}
108120

src/Task/Recurrence.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,16 @@ export class Recurrence {
7272
* Returns the dates of the next occurrence or null if there is no next occurrence.
7373
*
7474
* @param today - Optional date representing the completion date. Defaults to today.
75+
* @param dropScheduledDate - Optional boolean to drop the scheduled date from the next occurrence so long as a start or due date exists.
7576
*/
76-
public next(today = window.moment()): Occurrence | null {
77+
public next(today = window.moment(), dropScheduledDate: boolean = false): Occurrence | null {
7778
const nextReferenceDate = this.nextReferenceDate(today);
7879

7980
if (nextReferenceDate === null) {
8081
return null;
8182
}
8283

83-
return this.occurrence.next(nextReferenceDate);
84+
return this.occurrence.next(nextReferenceDate, dropScheduledDate);
8485
}
8586

8687
public identicalTo(other: Recurrence) {

src/Task/Task.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,8 @@ export class Task extends ListItem {
377377
return [toggledTask];
378378
}
379379

380-
const nextOccurrence = this.recurrence.next(today);
380+
const { dropScheduledDateOnRecurrence } = getSettings();
381+
const nextOccurrence = this.recurrence.next(today, dropScheduledDateOnRecurrence);
381382
if (nextOccurrence === null) {
382383
return [toggledTask];
383384
}

src/i18n/locales/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@
180180
"nextLine": {
181181
"description": "Enabling this will make the next recurrence of a task appear on the line below the completed task. Otherwise the next recurrence will appear before the completed one.",
182182
"name": "Next recurrence appears on the line below"
183+
},
184+
"dropScheduledDate": {
185+
"description": "Enabling this will make the next recurrence of a task have no scheduled date, unless the scheduled date is the only date the task has.",
186+
"name": "Drop scheduled date (only if Start or Due is present)"
183187
}
184188
},
185189
"seeTheDocumentation": "See the documentation",

tests/Task/Recurrence.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,41 @@ describe('identicalTo', () => {
228228
expect(date1Recurrence?.identicalTo(date2Recurrence)).toBe(false);
229229
});
230230
});
231+
232+
describe('Recurrence - with dropScheduledDateOnRecurrence', () => {
233+
it('drops the scheduledDate when dropScheduledDate is true', () => {
234+
// Arrange
235+
const recurrence = Recurrence.fromText({
236+
recurrenceRuleText: 'every month',
237+
occurrence: new Occurrence({
238+
startDate: moment('2022-01-01').startOf('day'),
239+
scheduledDate: moment('2022-01-04').startOf('day'),
240+
dueDate: moment('2022-01-10').startOf('day'),
241+
}),
242+
});
243+
244+
// Act
245+
const next = recurrence!.next(undefined, true);
246+
247+
// Assert
248+
expect(next!.startDate).toEqualMoment(moment('2022-02-01'));
249+
expect(next!.scheduledDate).toBeNull();
250+
expect(next!.dueDate).toEqualMoment(moment('2022-02-10'));
251+
});
252+
253+
it('does not drop the scheduledDate when it is the only date', () => {
254+
// Arrange
255+
const recurrence = Recurrence.fromText({
256+
recurrenceRuleText: 'every month',
257+
occurrence: new Occurrence({
258+
scheduledDate: moment('2022-01-04').startOf('day'),
259+
}),
260+
});
261+
262+
// Act
263+
const next = recurrence!.next(undefined, true);
264+
265+
// Assert
266+
expect(next!.scheduledDate).not.toBeNull();
267+
});
268+
});

0 commit comments

Comments
 (0)