Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "WIP: When friendly dates are enabled, group elements use frie… #737

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 19 additions & 29 deletions src/main/modules/Attributes.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
const attributes: Attributes = {
let attributes: Attributes = {
priority: {},
projects: {},
contexts: {},
due: {} as DateAttribute,
t: {} as DateAttribute,
due: {},
t: {},
rec: {},
pm: {},
created: {} as DateAttribute,
completed: {} as DateAttribute,
created: {},
completed: {},
};

function getDateAttributes(): DateAttributes {
return {
due: attributes.due,
t: attributes.t,
created: attributes.created,
completed: attributes.completed,
};
}

function incrementCount(countObject: any, key: any | null, notify: boolean): void {
if(key) {
let previousCount: number = parseInt(countObject[key]?.count) || 0;
Expand All @@ -30,35 +21,34 @@ function incrementCount(countObject: any, key: any | null, notify: boolean): voi
}

function updateAttributes(todoObjects: TodoObject[], sorting: Sorting[], reset: boolean) {

const attributeKeys = Object.keys(attributes) as AttributeKey[];

for (const key of attributeKeys) {

for (const attributeKey in attributes[key]) {

Object.keys(attributes).forEach((key) => {

Object.keys(attributes[key]).forEach((attributeKey) => {
(reset) ? attributes[key] = {} : attributes[key][attributeKey].count = 0
};
});

for (const todoObject of todoObjects) {
todoObjects.forEach((todoObject: TodoObject) => {
const value = todoObject[key as keyof TodoObject];
const notify: boolean = (key === 'due') ? !!todoObject?.notify : false;

if(Array.isArray(value)) {
for (const element of value) {
value.forEach((element) => {
if(element !== null) {
const attributeKey = element as keyof Attribute;

incrementCount(attributes[key], attributeKey, notify);
}
}
});
} else {
if(value !== null) {
incrementCount(attributes[key], value, notify);
}
}
}
});
attributes[key] = Object.fromEntries(Object.entries(attributes[key]).sort(([a], [b]) => a.localeCompare(b)));
}
});
attributes = Object.fromEntries(sorting.map((item) => [item.value, attributes[item.value]]));
}

export { attributes, getDateAttributes, updateAttributes };
export { attributes, updateAttributes };
14 changes: 7 additions & 7 deletions src/main/modules/DataRequest/CreateTodoObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ function createTodoObject(lineNumber: number, string: string, attributeType?: st
content = JsTodoTxtObject.toString().replaceAll(' [LB] ', String.fromCharCode(16));

const body = JsTodoTxtObject.body().replaceAll(' [LB] ', ' ');
const speakingDates = extractSpeakingDates(body);
const due = speakingDates.due?.date || null;
const dueString = speakingDates.due?.string || null;
const notify = speakingDates.due?.notify || false;
const t = speakingDates.t?.date || null;
const tString = speakingDates.t?.string || null;
const speakingDates: DateAttributes = extractSpeakingDates(body);
const due = speakingDates['due:']?.date || null;
const dueString = speakingDates['due:']?.string || null;
const notify = speakingDates['due:']?.notify || false;
const t = speakingDates['t:']?.date || null;
const tString = speakingDates['t:']?.string || null;
const hidden = extensions.some(extension => extension.key === 'h' && extension.value === '1');
const pm: string | number | null = extensions.find(extension => extension.key === 'pm')?.value || null;
const rec = extensions.find(extension => extension.key === 'rec')?.value || null;
Expand Down Expand Up @@ -97,4 +97,4 @@ function createTodoObjects(fileContent: string | null): TodoObject[] | [] {
return todoObjects;
}

export { createTodoObjects, createTodoObject, linesInFile };
export { createTodoObjects, createTodoObject, linesInFile };
19 changes: 3 additions & 16 deletions src/main/modules/DataRequest/SortAndGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { config } from '../../config';
import { getDateAttributes } from '../Attributes';
import { friendlyDateGroup } from '../Date';

function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]): TodoGroup {
const fileSorting: boolean = config.get('fileSorting');
Expand Down Expand Up @@ -33,24 +31,13 @@ function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]):
return 0;
}

function getGroupKey(todoObject: TodoObject, attributeKey: string) {
const useFriendlyDates = config.get('useHumanFriendlyDates');
const isDateAttribute = Object.keys(getDateAttributes()).includes(attributeKey);

if (useFriendlyDates && isDateAttribute) {
return friendlyDateGroup(todoObject[attributeKey]);
}

return todoObject[attributeKey];
}

function groupTodoObjectsByKey(todoObjects: TodoObject[], attributeKey: string) {
const grouped: TodoGroup = {};
for (const todoObject of todoObjects) {
const groupKey = getGroupKey(todoObject, attributeKey);
const groupKey = todoObject[attributeKey] || null;
if (!grouped[groupKey]) {
grouped[groupKey] = {
title: todoObject[attributeKey],
title: groupKey,
todoObjects: [],
visible: false
};
Expand Down Expand Up @@ -83,4 +70,4 @@ function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]):
return sortedAndGroupedTodoObjects;
}

export { sortAndGroupTodoObjects };
export { sortAndGroupTodoObjects };
78 changes: 14 additions & 64 deletions src/main/modules/Date.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Sugar from 'sugar';
import dayjs, { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
import { config } from '../config';

function mustNotify(date: Date): boolean {
Expand All @@ -9,9 +9,9 @@ function mustNotify(date: Date): boolean {
}

function replaceSpeakingDatesWithAbsoluteDates(string: string): string {
const speakingDates = extractSpeakingDates(string);
const due: DateAttribute = speakingDates.due;
const t: DateAttribute = speakingDates.t;
const speakingDates: DateAttributes = extractSpeakingDates(string);
const due: DateAttribute = speakingDates['due:'];
const t: DateAttribute = speakingDates['t:'];
if(due.date) {
string = string.replace(due.string!, due.date);
}
Expand Down Expand Up @@ -50,22 +50,22 @@ function processDateWithSugar(string: string, type: string): DateAttribute | nul
return lastMatch;
}

function extractSpeakingDates(body: string): Pick<DateAttributes, 'due'|'t'> {
const expressions: { pattern: RegExp, key: 'due'|'t', type: string }[] = [
{ pattern: /due:(?!(\d{4}-\d{2}-\d{2}))(.*?)(?=t:|$)/g, key: 'due', type: 'relative' },
{ pattern: /due:(\d{4}-\d{2}-\d{2})/g, key: 'due', type: 'absolute' },
{ pattern: /t:(?!(\d{4}-\d{2}-\d{2}))(.*?)(?=due:|$)/g, key: 't', type: 'relative' },
{ pattern: /t:(\d{4}-\d{2}-\d{2})/g, key: 't', type: 'absolute' },
function extractSpeakingDates(body: string): DateAttributes {
const expressions = [
{ pattern: /due:(?!(\d{4}-\d{2}-\d{2}))(.*?)(?=t:|$)/g, key: 'due:', type: 'relative' },
{ pattern: /due:(\d{4}-\d{2}-\d{2})/g, key: 'due:', type: 'absolute' },
{ pattern: /t:(?!(\d{4}-\d{2}-\d{2}))(.*?)(?=due:|$)/g, key: 't:', type: 'relative' },
{ pattern: /t:(\d{4}-\d{2}-\d{2})/g, key: 't:', type: 'absolute' },
];

const speakingDates: Pick<DateAttributes, 'due'|'t'> = {
'due': {
const speakingDates: DateAttributes = {
'due:': {
date: null,
string: null,
type: null,
notify: false,
},
't': {
't:': {
date: null,
string: null,
type: null,
Expand All @@ -86,54 +86,4 @@ function extractSpeakingDates(body: string): Pick<DateAttributes, 'due'|'t'> {
return speakingDates;
}

function friendlyDateGroup(date: Dayjs): FriendlyDateGroup | null {
const today = dayjs();

if (!date || !date.isValid()) {
return null;
}

if (date.isBefore(today.subtract(1, 'week'))) {
return 'before-last-week';
}

if (date.isBefore(today.subtract(1, 'day'))) {
return 'last-week';
}

if (date.isBefore(today)) {
return 'yesterday';
}

if (date.isSame(today)) {
return 'today';
}

if (date.isSame(today.add(1, 'day'))) {
return 'tomorrow';
}

if (date.isBefore(today.add(1, 'week').add(1, 'day'))) {
return 'this-week';
}

if (date.isBefore(today.add(2, 'week').add(1, 'day'))) {
return 'next-week';
}

if (date.isBefore(today.add(1, 'month').add(1, 'day'))) {
return 'this-month';
}

if (date.isBefore(today.add(2, 'month').add(1, 'day'))) {
return 'next-month';
}

return 'after-next-month';
}

export {
extractSpeakingDates,
friendlyDateGroup,
replaceSpeakingDatesWithAbsoluteDates
};
export { extractSpeakingDates, replaceSpeakingDatesWithAbsoluteDates };
10 changes: 4 additions & 6 deletions src/renderer/Grid/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import Divider from '@mui/material/Divider';
import dayjs from 'dayjs';
import updateLocale from 'dayjs/plugin/updateLocale';
import { friendlyDate } from 'renderer/Shared';
import type { i18n } from 'renderer/Settings/LanguageSelector';
import { type WithTranslation, withTranslation } from 'react-i18next';
import { getDateAttributes } from 'main/modules/Attributes';
import { i18n } from 'renderer/Settings/LanguageSelector';
import { WithTranslation, withTranslation } from 'react-i18next';
dayjs.extend(updateLocale);

interface FormatGroupElementProps {
Expand All @@ -19,13 +18,12 @@ interface FormatGroupElementProps {

function formatGroupElement({ groupElement, settings, t, todotxtAttribute }: FormatGroupElementProps) {
// If group element is a date, then format according to user preferences
const dateAttributeKeys = Object.keys(getDateAttributes());
if (
dateAttributeKeys.includes(todotxtAttribute)
['due', 't'].includes(todotxtAttribute)
&& dayjs(groupElement).isValid()
&& settings.useHumanFriendlyDates
) {
return friendlyDate(groupElement, todotxtAttribute, t).pop();
return friendlyDate(groupElement, todotxtAttribute, settings, t).pop();
}

// No transformation required: display as-is
Expand Down
78 changes: 39 additions & 39 deletions src/renderer/Shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import calendar from 'dayjs/plugin/calendar';
import weekday from 'dayjs/plugin/weekday';
import updateLocale from 'dayjs/plugin/updateLocale';
import { i18n } from './Settings/LanguageSelector';
import { friendlyDateGroup } from 'main/modules/Date';
dayjs.extend(relativeTime);
dayjs.extend(duration);
dayjs.extend(calendar);
Expand Down Expand Up @@ -69,47 +68,48 @@ export const friendlyDate = (value: string, attributeKey: string, settings: Sett
weekStart: settings.weekStart,
});

const today = dayjs();
const date = dayjs(value);
const group = friendlyDateGroup(date);

const results = [];

switch (group) {
case null:
// This should never happen, as `date` will always be a valid date
break;
case 'before-last-week':
results.push((attributeKey === 'due') ? t('drawer.attributes.overdue') : t('drawer.attributes.elapsed'));
break;
case 'last-week':
results.push((attributeKey === 'due') ? t('drawer.attributes.overdue') : t('drawer.attributes.elapsed'));
results.push(t('drawer.attributes.lastWeek'));
break;
case 'yesterday':
results.push((attributeKey === 'due') ? t('drawer.attributes.overdue') : t('drawer.attributes.elapsed'));
results.push(t('drawer.attributes.yesterday'));
break;
case 'today':
results.push(t('drawer.attributes.today'));
break;
case 'tomorrow':
results.push(t('drawer.attributes.tomorrow'));
break;
case 'this-week':
results.push(t('drawer.attributes.thisWeek'));
break;
case 'next-week':
results.push(t('drawer.attributes.nextWeek'));
break;
case 'this-month':
results.push(t('drawer.attributes.thisMonth'));
break;
case 'next-month':
results.push(t('drawer.attributes.nextMonth'));
break;
case 'after-next-month':
results.push(dayjs(date).format('YYYY-MM-DD'));
break;
if (date.isBefore(today, 'day')) {
results.push((attributeKey === 'due') ? t('drawer.attributes.overdue') : t('drawer.attributes.elapsed'));
}

if (date.isAfter(today.subtract(1, 'week').startOf('week').subtract(1, 'day')) && date.isBefore(today.subtract(1, 'week').endOf('week'))) {
results.push(t('drawer.attributes.lastWeek'));
}

if (date.isBefore(today.endOf('month')) && date.isAfter(today.subtract(1, 'day'), 'day')) {
results.push(t('drawer.attributes.thisMonth'));
}

if (date.isSame(today, 'week')) {
results.push(t('drawer.attributes.thisWeek'));
}

if (date.isSame(today.subtract(1, 'day'), 'day')) {
results.push(t('drawer.attributes.yesterday'));
}

if (date.isSame(today, 'day')) {
results.push(t('drawer.attributes.today'));
}

if (date.isSame(today.add(1, 'day'), 'day')) {
results.push(t('drawer.attributes.tomorrow'));
}

if (date.isSame(today.add(1, 'week'), 'week')) {
results.push(t('drawer.attributes.nextWeek'));
}

if (date.month() === today.add(1, 'month').month()) {
results.push(t('drawer.attributes.nextMonth'));
}

if (date.isAfter(today.add(1, 'month').endOf('month'))) {
results.push(dayjs(date).format('YYYY-MM-DD'));
}

return results;
Expand Down
Loading