From 97864c908aa058b4bc3fdd55cc523d234f6224e0 Mon Sep 17 00:00:00 2001 From: ransome1 Date: Mon, 1 Apr 2024 12:06:40 +0200 Subject: [PATCH] Refactoring --- src/__tests__/__mock__/recurrence.txt | 28 +- src/__tests__/__mock__/test.txt | 13 +- src/__tests__/main/ChangeCompleteState.tsx | 8 +- src/__tests__/main/CreateRecurringTodo.tsx | 2 +- src/__tests__/main/Date.tsx | 2 +- src/__tests__/main/Dialog.tsx | 6 +- src/__tests__/main/Filters.tsx | 6 +- src/__tests__/main/ProcessTodoObjects.tsx | 3 +- src/__tests__/main/Write.tsx | 251 +++++++++--------- src/main/config.tsx | 23 +- src/main/main.tsx | 3 +- src/main/modules/File/Active.tsx | 2 +- src/main/modules/File/Archive.tsx | 22 +- src/main/modules/File/Dialog.tsx | 37 +-- src/main/modules/File/File.tsx | 7 +- src/main/modules/File/Watcher.tsx | 4 +- src/main/modules/File/Write.tsx | 101 ++++--- src/main/modules/Filters/Filters.tsx | 43 ++- src/main/modules/Filters/Search.tsx | 35 +++ src/main/modules/IpcMain.tsx | 21 +- src/main/modules/Notifications.tsx | 3 +- .../ChangeCompleteState.tsx | 4 +- .../CreateRecurringTodo.tsx | 7 +- .../ProcessDataRequest/CreateTodoObjects.tsx | 12 +- .../ProcessDataRequest/ProcessDataRequest.tsx | 7 +- .../ProcessDataRequest/ProcessTodoObjects.tsx | 83 +----- src/main/modules/Tray.tsx | 6 +- src/types.tsx | 7 +- 28 files changed, 355 insertions(+), 391 deletions(-) create mode 100644 src/main/modules/Filters/Search.tsx diff --git a/src/__tests__/__mock__/recurrence.txt b/src/__tests__/__mock__/recurrence.txt index ca4e1c0d..72a81458 100644 --- a/src/__tests__/__mock__/recurrence.txt +++ b/src/__tests__/__mock__/recurrence.txt @@ -1,15 +1,15 @@ -2024-03-16 Line 1 rec:1d due:2024-03-17 -2024-03-16 Line 1 rec:w due:2024-03-23 -2024-03-16 Line 1 rec:2m due:2024-05-16 -2024-03-16 Line 1 rec:+1d due:2024-03-18 -2024-03-16 Line 1 rec:7w due:2024-05-04 -2024-03-16 Line 1 due:2023-07-24 rec:+1b -2024-03-16 taxes are due in one year t:2022-03-30 due:2022-04-30 rec:+1y -2024-03-16 Water plants @home +quick due:2024-03-23 t:2024-03-13 rec:1w -2024-03-16 Line 1 rec:+1d t:2023-09-20 -2024-03-16 Line 1 rec:1d pri:A due:2024-03-17 -2024-03-16 (A) Do something rec:d t:2024-03-17 @SomeContext -2024-03-16 Do something rec:0d -2024-03-16 Do something rec:0d due:2024-03-16 -2024-03-16 Do something rec:0d due:2024-03-16 t:2024-03-16 \ No newline at end of file +2024-04-01 Line 1 rec:1d due:2024-04-02 +2024-04-01 Line 1 rec:w due:2024-04-08 +2024-04-01 Line 1 rec:2m due:2024-06-01 +2024-04-01 Line 1 rec:+1d due:2024-04-03 +2024-04-01 Line 1 rec:7w due:2024-05-20 +2024-04-01 Line 1 due:2023-07-24 rec:+1b +2024-04-01 taxes are due in one year t:2022-03-30 due:2022-04-30 rec:+1y +2024-04-01 Water plants @home +quick due:2024-04-08 t:2024-03-29 rec:1w +2024-04-01 Line 1 rec:+1d t:2023-09-20 +2024-04-01 Line 1 rec:1d pri:A due:2024-04-02 +2024-04-01 (A) Do something rec:d t:2024-04-02 @SomeContext +2024-04-01 Do something rec:0d +2024-04-01 Do something rec:0d due:2024-04-01 +2024-04-01 Do something rec:0d due:2024-04-01 t:2024-04-01 \ No newline at end of file diff --git a/src/__tests__/__mock__/test.txt b/src/__tests__/__mock__/test.txt index 40ceba3b..80735e7e 100644 --- a/src/__tests__/__mock__/test.txt +++ b/src/__tests__/__mock__/test.txt @@ -1,11 +1,4 @@ Line 1 -Edited line -Multi line 1Multi line 2Multi line 3 -Updated line -Append 1 -Append 2 -New line with relative threshold date t:June 3rd, 2005 -Line4 -Line5 -Line6 -Multi line 1Multi line 2Multi line 3 \ No newline at end of file +Line 2 +Line 3 +New line \ No newline at end of file diff --git a/src/__tests__/main/ChangeCompleteState.tsx b/src/__tests__/main/ChangeCompleteState.tsx index f8ef72c3..57b5e359 100644 --- a/src/__tests__/main/ChangeCompleteState.tsx +++ b/src/__tests__/main/ChangeCompleteState.tsx @@ -13,13 +13,13 @@ describe('Marking todo as complete and vice versa', () => { jest.clearAllMocks(); }); - test('Unfinished todo is being marked as complete', async () => { - const updatedTodoObject = await changeCompleteState('(C) +testProject5 test0 @testContext due:2023-01-02', true); + test('Unfinished todo is being marked as complete', () => { + const updatedTodoObject = changeCompleteState('(C) +testProject5 test0 @testContext due:2023-01-02', true); expect(updatedTodoObject?.toString()).toEqual('x ' + date + ' ' + date + ' +testProject5 test0 @testContext due:2023-01-02 pri:C'); }); - test('Finished todo is being marked as incomplete', async () => { - const updatedTodoObject = await changeCompleteState('x 2023-07-06 2023-07-01 +testProject2 test1 @testContext due:2023-12-12 pri:C', false); + test('Finished todo is being marked as incomplete', () => { + const updatedTodoObject = changeCompleteState('x 2023-07-06 2023-07-01 +testProject2 test1 @testContext due:2023-12-12 pri:C', false); expect(updatedTodoObject?.toString()).toEqual('(C) 2023-07-01 +testProject2 test1 @testContext due:2023-12-12 pri:C'); }); diff --git a/src/__tests__/main/CreateRecurringTodo.tsx b/src/__tests__/main/CreateRecurringTodo.tsx index 6cc77795..edbcfb53 100644 --- a/src/__tests__/main/CreateRecurringTodo.tsx +++ b/src/__tests__/main/CreateRecurringTodo.tsx @@ -3,7 +3,7 @@ import { createRecurringTodo } from '../../main/modules/ProcessDataRequest/Creat import dayjs from 'dayjs'; jest.mock('../../main/modules/ProcessDataRequest/CreateTodoObjects', () => ({ - lines: [''], + linesInFile: [''], })); jest.mock('../../main/config', () => ({ diff --git a/src/__tests__/main/Date.tsx b/src/__tests__/main/Date.tsx index 1b05c4c7..561296fc 100644 --- a/src/__tests__/main/Date.tsx +++ b/src/__tests__/main/Date.tsx @@ -2,7 +2,7 @@ import { extractSpeakingDates, replaceSpeakingDatesWithAbsoluteDates } from '../ import dayjs from 'dayjs'; jest.mock('../../main/modules/File/Write', () => ({ - writeTodoObjectToFile: jest.fn(), + writeContentToFile: jest.fn(), })); jest.mock('../../main/config', () => ({ diff --git a/src/__tests__/main/Dialog.tsx b/src/__tests__/main/Dialog.tsx index 3e970cf2..852cefb3 100644 --- a/src/__tests__/main/Dialog.tsx +++ b/src/__tests__/main/Dialog.tsx @@ -75,7 +75,7 @@ describe('createFile', () => { jest.clearAllMocks(); }); - it('should call addFile after successfully creating a file', async () => { + it('should call addFile after successfully creating a file', async() => { (dialog.showSaveDialog as jest.Mock).mockResolvedValueOnce({ canceled: false, filePath: './src/__tests__/__mock__/fileDialog.txt', @@ -90,11 +90,11 @@ describe('createFile', () => { filters: [{ name: 'Text files', extensions: ['txt'] }, { name: 'All files', extensions: ['*'] }], }); - expect(fs.writeFile).toHaveBeenCalledWith('./src/__tests__/__mock__/fileDialog.txt', ''); + expect(fs.writeFile).toHaveBeenCalledWith('./src/__tests__/__mock__/fileDialog.txt', '', 'utf8'); expect(addFile).toHaveBeenCalledWith('./src/__tests__/__mock__/fileDialog.txt', null); }); - it('should not call addFile when file creation is canceled', async () => { + it('should not call addFile when file creation is canceled', async() => { (dialog.showSaveDialog as jest.Mock).mockResolvedValueOnce({ canceled: true, filePath: undefined, diff --git a/src/__tests__/main/Filters.tsx b/src/__tests__/main/Filters.tsx index d81e1067..21918bb0 100644 --- a/src/__tests__/main/Filters.tsx +++ b/src/__tests__/main/Filters.tsx @@ -1,4 +1,4 @@ -import { applyFilters } from '../../main/modules/Filters/Filters'; +import { applyAttributes } from '../../main/modules/Filters/Filters'; describe('Should filter todos based on passed filters', () => { const todoObjects = [ @@ -9,7 +9,7 @@ describe('Should filter todos based on passed filters', () => { test('should return all todo objects if no filters are provided', () => { const filters = null; - const result = applyFilters(todoObjects, filters); + const result = applyAttributes(todoObjects, filters); expect(result).toEqual(todoObjects); }); @@ -22,7 +22,7 @@ describe('Should filter todos based on passed filters', () => { { id: 2, body: 'Test', created: null, complete: true, completed: null, priority: null, contexts: null, projects: ['Project 2'], due: '2023-02-01', dueString: '2023-02-01', t: null, tString: null, rec: null, hidden: false, pm: null, visible: false, string: '' }, { id: 3, body: 'Test', created: null, complete: false, completed: null, priority: null, contexts: null, projects: ['Project 1'], due: '2023-03-01', dueString: '2023-03-01', t: null, tString: null, rec: null, hidden: false, pm: null, visible: true, string: '' }, ]; - const result = applyFilters(todoObjects, filters); + const result = applyAttributes(todoObjects, filters); expect(result).toEqual(expected); }); diff --git a/src/__tests__/main/ProcessTodoObjects.tsx b/src/__tests__/main/ProcessTodoObjects.tsx index 287ac022..0e4c0f4b 100644 --- a/src/__tests__/main/ProcessTodoObjects.tsx +++ b/src/__tests__/main/ProcessTodoObjects.tsx @@ -1,6 +1,7 @@ import fs from 'fs/promises'; import { createTodoObjects } from '../../main/modules/ProcessDataRequest/CreateTodoObjects'; -import { applySearchString, countTodoObjects, sortAndGroupTodoObjects, flattenTodoObjects } from '../../main/modules/ProcessDataRequest/ProcessTodoObjects'; +import { applySearchString } from '../../main/modules/Filters/Search'; +import { countTodoObjects, sortAndGroupTodoObjects, flattenTodoObjects } from '../../main/modules/ProcessDataRequest/ProcessTodoObjects'; jest.mock('../../main/config', () => ({ config: { diff --git a/src/__tests__/main/Write.tsx b/src/__tests__/main/Write.tsx index 9a765c61..42c353e3 100644 --- a/src/__tests__/main/Write.tsx +++ b/src/__tests__/main/Write.tsx @@ -1,5 +1,5 @@ -import fs from 'fs/promises'; -import { writeTodoObjectToFile, removeLineFromFile } from '../../main/modules/File/Write'; +import fs from 'fs'; +import { prepareContentForWriting, removeLineFromFile } from '../../main/modules/File/Write'; import { config } from '../../main/config'; import dayjs from 'dayjs'; @@ -29,136 +29,137 @@ jest.mock('../../main/config', () => ({ })); jest.mock('../../main/modules/ProcessDataRequest/CreateTodoObjects', () => ({ - lines: ['Line 1', 'Line 2', 'Line 3'], + linesInFile: ['Line 1', 'Line 2', 'Line 3'], })); describe('Writing to file', () => { - beforeEach(async () => { + beforeEach(() => { jest.clearAllMocks(); }); - test('should fail if no string is provided', async () => { - await expect(writeTodoObjectToFile(-1, '')).rejects.toThrow("No string provided, won't write empty todo to file"); + test('should write a new line when id is not provided', () => { + prepareContentForWriting(-1, 'New line'); + //const fileContent = fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + fs.readFile('./src/__tests__/__mock__/test.txt', (error, data) => { + if (error) throw error; + console.log(data) + //expect(data).toEqual('Line 1\nLine 2\nLine 3\nNew line'); + //console.log(data); + }); }); - test('should write a new line when id is not provided', async () => { - await writeTodoObjectToFile(-1, 'New line'); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual('Line 1\nLine 2\nLine 3\nNew line'); - }); - - test('should write a new line when id is not provided and append a creation date', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'appendCreationDate') { - return true; - } - return originalGet.call(config, key); - }; - await writeTodoObjectToFile(-1, 'New line with creation date'); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date`); - config.get = originalGet; - }); - - test('should write a new line when id is not provided and convert a relative (speaking) date to an absolute date', async () => { - await writeTodoObjectToFile(-1, 'New line with relative threshold date t:June 3rd, 2005'); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:2005-06-03`); - }); - - test('should overwrite a line when id is provided and NOT convert a relative (speaking) date to an absolute date', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'convertRelativeToAbsoluteDates') { - return false; - } - return originalGet.call(config, key); - }; - await writeTodoObjectToFile(5, 'New line with relative threshold date t:June 3rd, 2005'); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); - config.get = originalGet; - }); - - test('should overwrite a line when id is provided', async () => { - await writeTodoObjectToFile(1, 'Edited line'); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); - }); - - test('should delete a line when remove is true', async () => { - await removeLineFromFile(2); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); - }); - - test('should append 3 new lines at the end of the file', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'bulkTodoCreation') { - return true; - } - return originalGet.call(config, key); - }; - - const content = 'Line4\nLine5\nLine6'; - - await writeTodoObjectToFile(-1, content); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6`); - config.get = originalGet; - }); - - test('should update a specific line and append 2 lines to the updated line', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'bulkTodoCreation') { - return true; - } - return originalGet.call(config, key); - }; - - const content = 'Updated line\nAppend 1\nAppend 2'; - - await writeTodoObjectToFile(3, content); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6`); - config.get = originalGet; - }); - - test('should append a multi line todo', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'bulkTodoCreation') { - return false; - } - return originalGet.call(config, key); - }; - - const content = 'Multi line 1\nMulti line 2\nMulti line 3'; - - await writeTodoObjectToFile(-1, content); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6\nMulti line 1Multi line 2Multi line 3`); - config.get = originalGet; - }); - - test('should update line with a multi line todo', async () => { - const originalGet = config.get; - config.get = (key: string) => { - if(key === 'bulkTodoCreation') { - return false; - } - return originalGet.call(config, key); - }; - - const content = 'Multi line 1\nMulti line 2\nMulti line 3'; - - await writeTodoObjectToFile(2, content); - const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); - expect(fileContent).toEqual(`Line 1\nEdited line\nMulti line 1Multi line 2Multi line 3\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6\nMulti line 1Multi line 2Multi line 3`); - config.get = originalGet; - }); + // test('should write a new line when id is not provided and append a creation date', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'appendCreationDate') { + // return true; + // } + // return originalGet.call(config, key); + // }; + // await prepareContentForWriting(-1, 'New line with creation date'); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date`); + // config.get = originalGet; + // }); + + // test('should write a new line when id is not provided and convert a relative (speaking) date to an absolute date', async () => { + // await prepareContentForWriting(-1, 'New line with relative threshold date t:June 3rd, 2005'); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:2005-06-03`); + // }); + + // test('should overwrite a line when id is provided and NOT convert a relative (speaking) date to an absolute date', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'convertRelativeToAbsoluteDates') { + // return false; + // } + // return originalGet.call(config, key); + // }; + // await prepareContentForWriting(5, 'New line with relative threshold date t:June 3rd, 2005'); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nLine 2\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); + // config.get = originalGet; + // }); + + // test('should overwrite a line when id is provided', async () => { + // await prepareContentForWriting(1, 'Edited line'); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nLine 3\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); + // }); + + // test('should delete a line when remove is true', async () => { + // removeLineFromFile(2); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005`); + // }); + + // test('should append 3 new lines at the end of the file', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'bulkTodoCreation') { + // return true; + // } + // return originalGet.call(config, key); + // }; + + // const content = 'Line4\nLine5\nLine6'; + + // await prepareContentForWriting(-1, content); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\n${date} New line with creation date\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6`); + // config.get = originalGet; + // }); + + // test('should update a specific line and append 2 lines to the updated line', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'bulkTodoCreation') { + // return true; + // } + // return originalGet.call(config, key); + // }; + + // const content = 'Updated line\nAppend 1\nAppend 2'; + + // await prepareContentForWriting(3, content); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6`); + // config.get = originalGet; + // }); + + // test('should append a multi line todo', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'bulkTodoCreation') { + // return false; + // } + // return originalGet.call(config, key); + // }; + + // const content = 'Multi line 1\nMulti line 2\nMulti line 3'; + + // await prepareContentForWriting(-1, content); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nNew line\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6\nMulti line 1Multi line 2Multi line 3`); + // config.get = originalGet; + // }); + + // test('should update line with a multi line todo', async () => { + // const originalGet = config.get; + // config.get = (key: string) => { + // if(key === 'bulkTodoCreation') { + // return false; + // } + // return originalGet.call(config, key); + // }; + + // const content = 'Multi line 1\nMulti line 2\nMulti line 3'; + + // await prepareContentForWriting(2, content); + // const fileContent = await fs.readFile('./src/__tests__/__mock__/test.txt', 'utf8'); + // expect(fileContent).toEqual(`Line 1\nEdited line\nMulti line 1Multi line 2Multi line 3\nUpdated line\nAppend 1\nAppend 2\nNew line with relative threshold date t:June 3rd, 2005\nLine4\nLine5\nLine6\nMulti line 1Multi line 2Multi line 3`); + // config.get = originalGet; + // }); }); diff --git a/src/main/config.tsx b/src/main/config.tsx index e63a22bd..c9354b5b 100644 --- a/src/main/config.tsx +++ b/src/main/config.tsx @@ -4,6 +4,7 @@ import { app, nativeTheme } from 'electron'; import fs from 'fs'; import { mainWindow } from './main'; import { createFileWatcher } from './modules/File/Watcher'; +import { writeToFile } from './modules/File/Write'; import { createTray } from './modules/Tray'; import { processDataRequest, searchString } from './modules/ProcessDataRequest/ProcessDataRequest'; import handleTheme from './modules/Theme'; @@ -12,11 +13,7 @@ import crypto from 'crypto'; Store.initRenderer(); -const environment: string | undefined = process.env.NODE_ENV; - -const anonymousUserId: string = crypto.randomUUID() || null; - -const userDataDirectory: string = (environment === 'development') ? path.join(app.getPath('userData'), 'userData-Development') : path.join(app.getPath('userData'), 'userData'); +const userDataDirectory: string = (process.env.NODE_ENV === 'development') ? path.join(app.getPath('userData'), 'userData-Development') : path.join(app.getPath('userData'), 'userData'); if(!fs.existsSync(userDataDirectory)) fs.mkdirSync(userDataDirectory) @@ -24,7 +21,7 @@ console.log('config.ts: sleek userdata is located at: ' + userDataDirectory); const customStylesPath: string = path.join(userDataDirectory, 'customStyles.css'); if(!fs.existsSync(customStylesPath)) { - fs.writeFileSync(customStylesPath, ''); + writeToFile('', customStylesPath, null) } const config: Store = new Store({ @@ -78,7 +75,7 @@ const config: Store = new Store({ }, '2.0.1': store => { console.log('Migrating from 2.0.0 → 2.0.1'); - store.set('anonymousUserId', anonymousUserId); + store.set('anonymousUserId', crypto.randomUUID()); }, '2.0.2': store => { console.log('Migrating from 2.0.1 → 2.0.2'); @@ -138,7 +135,7 @@ const notifiedTodoObjectsStorage = new Store<{}>({ cwd: userDataDirectory, name: if(!fs.existsSync(notifiedTodoObjectsPath)) { const defaultNotifiedTodoObjectsData = {}; - fs.writeFileSync(notifiedTodoObjectsPath, JSON.stringify(defaultNotifiedTodoObjectsData)); + writeToFile(JSON.stringify(defaultNotifiedTodoObjectsData), notifiedTodoObjectsPath, null) } filter.onDidChange('attributes', async () => { @@ -169,13 +166,17 @@ config.onDidChange('files', (newValue: FileObject[] | undefined) => { }); config.onDidChange('colorTheme', (colorTheme) => { - if(colorTheme === 'system' || colorTheme === 'light' || colorTheme === 'dark') { - nativeTheme.themeSource = colorTheme; + try { + if(colorTheme === 'system' || colorTheme === 'light' || colorTheme === 'dark') { + nativeTheme.themeSource = colorTheme; + } + } catch (error: any) { + console.error(error); } }); config.onDidChange('menuBarVisibility', (menuBarVisibility) => { - mainWindow.setMenuBarVisibility(menuBarVisibility); + mainWindow?.setMenuBarVisibility(menuBarVisibility || true); }); config.onDidChange('tray', () => { diff --git a/src/main/main.tsx b/src/main/main.tsx index 6d1723ae..1790fcfe 100644 --- a/src/main/main.tsx +++ b/src/main/main.tsx @@ -147,8 +147,7 @@ const createMainWindow = () => { eventListeners.handleMaximize = handleMaximize eventListeners.handleUnmaximize = handleUnmaximize; - const tray: boolean = config.get('tray'); - if(tray) { + if(config.get('tray')) { createTray(); } diff --git a/src/main/modules/File/Active.tsx b/src/main/modules/File/Active.tsx index 0339bf92..d2118f36 100644 --- a/src/main/modules/File/Active.tsx +++ b/src/main/modules/File/Active.tsx @@ -5,4 +5,4 @@ export function getActiveFile(): FileObject | null { if(files.length === 0) return null; const activeIndex = files.findIndex((file) => file.active); return files[activeIndex]; -} +} \ No newline at end of file diff --git a/src/main/modules/File/Archive.tsx b/src/main/modules/File/Archive.tsx index b7f028e6..69c592af 100644 --- a/src/main/modules/File/Archive.tsx +++ b/src/main/modules/File/Archive.tsx @@ -1,14 +1,13 @@ -import fs from 'fs/promises'; import { getActiveFile } from './Active'; import { readFileContent } from './File'; +import { writeToFile } from './Write'; import { mainWindow } from '../../main'; -async function replaceFileContent(string: string, filePath: string) { - await fs.writeFile(filePath, string, 'utf8'); -} - function handleRequestArchive(): void { - const activeFile = getActiveFile(); + const activeFile: FileObject | null = getActiveFile(); + if(!activeFile) { + throw new Error('Todo file is not defined'); + } mainWindow!.webContents.send('triggerArchiving', Boolean(activeFile?.doneFilePath)); } @@ -30,9 +29,8 @@ async function readFilteredFileContent(filePath: string, bookmark: string | null async function archiveTodos(): Promise { const activeFile: FileObject | null = getActiveFile(); - - if(activeFile === null) { - return 'No active file defined'; + if(!activeFile) { + throw new Error('Todo file is not defined'); } if(activeFile.doneFilePath === null) { @@ -49,9 +47,9 @@ async function archiveTodos(): Promise { const todosFromDoneFile: string | null = await readFileContent(activeFile.doneFilePath, activeFile.doneFileBookmark); - await replaceFileContent(todosFromDoneFile + '\n' + completedTodos, activeFile.doneFilePath); - - await replaceFileContent(uncompletedTodos, activeFile.todoFilePath); + await writeToFile(todosFromDoneFile + '\n' + completedTodos, activeFile.doneFilePath, activeFile.doneFileBookmark); + + await writeToFile(uncompletedTodos, activeFile.todoFilePath, activeFile.todoFileBookmark); return 'Successfully archived'; } diff --git a/src/main/modules/File/Dialog.tsx b/src/main/modules/File/Dialog.tsx index a94aa23e..dd8f8ae2 100644 --- a/src/main/modules/File/Dialog.tsx +++ b/src/main/modules/File/Dialog.tsx @@ -1,7 +1,7 @@ import { app, dialog, OpenDialogReturnValue, SaveDialogReturnValue } from 'electron'; import path from 'path'; -import fs from 'fs/promises'; import { addFile, addDoneFile } from './File'; +import { writeToFile } from './Write'; const dialogFilters = [ { @@ -24,13 +24,16 @@ async function openFile(setDoneFile: boolean): Promise { const filePath: string = result.filePaths[0]; const bookmark: string | null = result.bookmarks?.[0] || null; - if(setDoneFile) { - addDoneFile(filePath, bookmark); - } else { - addFile(filePath, bookmark); + try { + if(setDoneFile) { + addDoneFile(filePath, bookmark); + } else { + addFile(filePath, bookmark); + } + } catch(error: any) { + console.error(error); } } - return; } async function createFile(setDoneFile: boolean): Promise { @@ -40,25 +43,23 @@ async function createFile(setDoneFile: boolean): Promise { filters: dialogFilters, securityScopedBookmarks: true, }); + if(!result.canceled && result.filePath) { const filePath: string = result.filePath; const bookmark: string | null = result.bookmark || null; - if(process.mas && bookmark) { - const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(bookmark); - await fs.writeFile(filePath, ''); - stopAccessingSecurityScopedResource() - } else { - await fs.writeFile(filePath, ''); - } + writeToFile('', filePath, bookmark) - if(setDoneFile) { - addDoneFile(filePath, bookmark); - } else { - addFile(filePath, bookmark); + try { + if(setDoneFile) { + addDoneFile(filePath, bookmark); + } else { + addFile(filePath, bookmark); + } + } catch(error: any) { + console.error(error); } } - return; } export { diff --git a/src/main/modules/File/File.tsx b/src/main/modules/File/File.tsx index 42a26317..92b8105b 100644 --- a/src/main/modules/File/File.tsx +++ b/src/main/modules/File/File.tsx @@ -7,10 +7,6 @@ import path from 'path'; import { mainWindow } from '../../main'; async function readFileContent(filePath: string, bookmark: string | null): Promise { - if(!filePath) { - return null; - } - let fileContent; if(process.mas && bookmark) { @@ -48,8 +44,7 @@ function addFile(filePath: string, bookmark: string | null) { createMenu(files); - const tray = config.get('tray'); - if(tray) { + if(config.get('tray')) { createTray(); } diff --git a/src/main/modules/File/Watcher.tsx b/src/main/modules/File/Watcher.tsx index 0432b050..f5b8d996 100644 --- a/src/main/modules/File/Watcher.tsx +++ b/src/main/modules/File/Watcher.tsx @@ -17,9 +17,7 @@ function createFileWatcher(files: FileObject[]): void { config.set('files', files) } - const chokidarOptions = config.get('chokidarOptions'); - - watcher = chokidar.watch(files.map((file) => file.todoFilePath), chokidarOptions); + watcher = chokidar.watch(files.map((file) => file.todoFilePath), config.get('chokidarOptions')); watcher .on('add', (file) => { diff --git a/src/main/modules/File/Write.tsx b/src/main/modules/File/Write.tsx index 3c9c7cbc..cfe2bcba 100644 --- a/src/main/modules/File/Write.tsx +++ b/src/main/modules/File/Write.tsx @@ -1,80 +1,71 @@ import { app } from 'electron'; -import fs from 'fs/promises'; +import fs from 'fs'; import { Item } from 'jstodotxt'; -import { lines } from '../ProcessDataRequest/CreateTodoObjects'; +import { linesInFile } from '../ProcessDataRequest/CreateTodoObjects'; import { getActiveFile } from './Active'; import { config } from '../../config'; import { replaceSpeakingDatesWithAbsoluteDates } from '../Date'; -async function removeLineFromFile(id: number): Promise { +function writeToFile(string: string, filePath: string, bookmark: string | null) { + const stopAccessingSecurityScopedResource = (process.mas && bookmark) ? app.startAccessingSecurityScopedResource(bookmark) : null; + fs.writeFile(filePath, string, (error) => { + if (error) return error; + console.info('Written to file'); + if(stopAccessingSecurityScopedResource) stopAccessingSecurityScopedResource() + }); +} + +function removeLineFromFile(lineNumber: number): string { const activeFile: FileObject | null = getActiveFile(); if(!activeFile) { - throw new Error('No active file'); - } - const bookmark = activeFile.todoFileBookmark; - const todoFilePath = activeFile.todoFilePath; - - lines.splice(id, 1); - const modifiedContent = lines.join('\n'); - - if(process.mas && bookmark) { - const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(bookmark); - await fs.writeFile(todoFilePath, modifiedContent, 'utf8'); - stopAccessingSecurityScopedResource() - } else { - await fs.writeFile(todoFilePath, modifiedContent, 'utf8'); + throw new Error('No active file found'); + } else if(typeof lineNumber !== 'number') { + throw new Error(`No line number passed, can't delete without it`); } - - return `Line ${id} removed from file`; + linesInFile.splice(lineNumber, 1); + writeToFile(linesInFile.join('\n'), activeFile.todoFilePath, activeFile.todoFileBookmark); + return `Line ${lineNumber} removed from file`; } -async function writeTodoObjectToFile(id: number, string: string): Promise { +function prepareContentForWriting(lineNumber: number, string: string) { const activeFile: FileObject | null = getActiveFile(); if(!activeFile) { - throw new Error('Todo file is not defined'); + throw new Error('No active file found'); + } else if(!string) { + throw new Error('No content passed'); } - const bookmark = activeFile.todoFileBookmark; - const todoFilePath = activeFile.todoFilePath; - const bulkTodoCreation: boolean = config.get('bulkTodoCreation'); - const convertRelativeToAbsoluteDates = config.get('convertRelativeToAbsoluteDates'); - const appendCreationDate = config.get('appendCreationDate'); - - const content = - (bulkTodoCreation) - ? string.replaceAll(String.fromCharCode(16), '\n') - : string.replaceAll(/\n/g, String.fromCharCode(16)); + let linesToAdd; - const linesToWrite = content.split('\n').filter(line => line.trim() !== ''); + if(config.get('bulkTodoCreation')) { + linesToAdd = string.replaceAll(String.fromCharCode(16), '\n'); + } else { + linesToAdd = string.replaceAll(/\n/g, String.fromCharCode(16)); + } - if(linesToWrite.length === 0 && id < 1) { - throw new Error("No string provided, won't write empty todo to file"); + if(config.get('convertRelativeToAbsoluteDates')) { + linesToAdd = replaceSpeakingDatesWithAbsoluteDates(linesToAdd); + } + + linesToAdd = linesToAdd.split('\n'); + + if(lineNumber >= 0) { + linesInFile[lineNumber] = linesToAdd.join('\n'); } else { - if(convertRelativeToAbsoluteDates) { - for (let i = 0; i < linesToWrite.length; i++) { - linesToWrite[i] = replaceSpeakingDatesWithAbsoluteDates(linesToWrite[i]); - } - } - if(id >= 0) { - lines[id] = linesToWrite.join('\n'); - } else { - for (let i = 0; i < linesToWrite.length; i++) { - const JsTodoTxtObject = new Item(linesToWrite[i]); - if(appendCreationDate && !JsTodoTxtObject.created()) { + for (let i = 0; i < linesToAdd.length; i++) { + if(config.get('appendCreationDate')) { + const JsTodoTxtObject = new Item(linesToAdd[i]); + if(!JsTodoTxtObject.created()) { JsTodoTxtObject.setCreated(new Date()); } - lines.push(JsTodoTxtObject.toString()); + linesInFile.push(JsTodoTxtObject.toString()); + } else { + linesInFile.push(linesToAdd[i]); } } } - - if(process.mas && bookmark) { - const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(bookmark); - await fs.writeFile(todoFilePath, lines.join('\n'), 'utf8'); - stopAccessingSecurityScopedResource() - } else { - await fs.writeFile(todoFilePath, lines.join('\n'), 'utf8'); - } + + writeToFile(linesInFile.join('\n'), activeFile.todoFilePath, activeFile.todoFileBookmark); } -export { writeTodoObjectToFile, removeLineFromFile }; +export { prepareContentForWriting, removeLineFromFile, writeToFile }; diff --git a/src/main/modules/Filters/Filters.tsx b/src/main/modules/Filters/Filters.tsx index df75677c..75851941 100644 --- a/src/main/modules/Filters/Filters.tsx +++ b/src/main/modules/Filters/Filters.tsx @@ -1,10 +1,13 @@ -function applyFilters(todoObjects: TodoObject[], filters: Filters | null): TodoObject[] { +import { config } from '../../config'; +import dayjs from 'dayjs'; + +function applyAttributes(todoObjects: TodoObject[], filters: Filters | null): TodoObject[] { return todoObjects.map((todoObject: TodoObject) => { if (!todoObject.visible) { return todoObject; } - const isVisible = Object.entries(filters || {}).every(([key, filterArray]: [string, Filter[]]) => { + todoObject.visible = Object.entries(filters || {}).every(([key, filterArray]: [string, Filter[]]) => { if (filterArray.length === 0) { return true; } @@ -28,10 +31,42 @@ function applyFilters(todoObjects: TodoObject[], filters: Filters | null): TodoO }); }); - todoObject.visible = isVisible; + return todoObject; + }); +} +function handleCompletedTodoObjects(todoObjects: TodoObject[]): TodoObject[] | false { + const showCompleted: boolean = config.get('showCompleted'); + return todoObjects.map((todoObject: TodoObject) => { + if(todoObject.complete && !showCompleted) { + return false; + } else { + return todoObject; + } + }); +} + +function handleHiddenTodoObjects(todoObjects: TodoObject[]): TodoObject[] { + return todoObjects.map((todoObject: TodoObject) => { + if(!todoObject.visible) return todoObject; + todoObject.visible = todoObject.visible && !todoObject.hidden; return todoObject; }); } -export { applyFilters }; +function handleTodoObjectsDates(todoObjects: TodoObject[]): TodoObject[] { + const thresholdDateInTheFuture: boolean = config.get('thresholdDateInTheFuture'); + const dueDateInTheFuture: boolean = config.get('dueDateInTheFuture'); + + return todoObjects.filter((todoObject: TodoObject) => { + if (!todoObject.visible) return true; + + const thresholdDate = dayjs(todoObject?.t); + const dueDate = dayjs(todoObject?.due); + + return !(thresholdDate && thresholdDate.isAfter(dayjs()) && !thresholdDateInTheFuture) && + !(dueDate && dueDate.isAfter(dayjs()) && !dueDateInTheFuture); + }); +} + +export { applyAttributes, handleCompletedTodoObjects, handleHiddenTodoObjects, handleTodoObjectsDates }; \ No newline at end of file diff --git a/src/main/modules/Filters/Search.tsx b/src/main/modules/Filters/Search.tsx new file mode 100644 index 00000000..93e62146 --- /dev/null +++ b/src/main/modules/Filters/Search.tsx @@ -0,0 +1,35 @@ +import * as FilterLang from './FilterLang.js'; +import { runQuery } from './FilterQuery'; +import { createTodoObject } from '../ProcessDataRequest/CreateTodoObjects'; + +function applySearchString(searchString: string, todoObjects: TodoObject[]): TodoObject[] { + try { + const query = FilterLang.parse(searchString); + return todoObjects.map(todoObject => { + if(!todoObject.visible) return todoObject; + todoObject.visible = runQuery(todoObject, query); + return todoObject; + }); + } catch (error) { + const lowerSearchString = searchString.toLowerCase(); + return Object.values(todoObjects) + .flat() + .map(todoObject => { + if(!todoObject.visible) return todoObject; + todoObject.visible = todoObject?.string?.toLowerCase().includes(lowerSearchString) || false; + return todoObject; + }) as TodoObject[]; + } +} + +function checkForSearchMatches(todoString: string, searchString: string) { + try { + const todoObject = createTodoObject(-1, todoString); + const query = FilterLang.parse(searchString); + return runQuery(todoObject, query); + } catch (error) { + return todoString.toLowerCase().includes(searchString); + } +} + +export { applySearchString, checkForSearchMatches}; \ No newline at end of file diff --git a/src/main/modules/IpcMain.tsx b/src/main/modules/IpcMain.tsx index 80e64c3e..952f77ff 100644 --- a/src/main/modules/IpcMain.tsx +++ b/src/main/modules/IpcMain.tsx @@ -2,7 +2,7 @@ import { shell } from 'electron'; import { ipcMain, app, IpcMainEvent, clipboard } from 'electron'; import { processDataRequest } from './ProcessDataRequest/ProcessDataRequest'; import { changeCompleteState } from './ProcessDataRequest/ChangeCompleteState'; -import { writeTodoObjectToFile, removeLineFromFile } from './File/Write'; +import { prepareContentForWriting, removeLineFromFile } from './File/Write'; import { archiveTodos, handleRequestArchive } from './File/Archive'; import { config, filter, notifiedTodoObjectsStorage } from '../config'; import { addFile, setFile, removeFile } from './File/File'; @@ -40,18 +40,17 @@ function handleUpdateTodoObject(event: IpcMainEvent, index: number, string: stri async function handleWriteTodoToFile(event: IpcMainEvent, index: number, string: string, state: boolean, attributeType: string, attributeValue: string): Promise { try { - let todoObject; if(attributeType && attributeValue) { - todoObject = createTodoObject(index, string, attributeType, attributeValue); - if(!todoObject.string) return; - const response = await writeTodoObjectToFile(index, todoObject.string); - event.reply('writeTodoToFile', response); - return; + const todoObject = createTodoObject(index, string, attributeType, attributeValue); + //const response = await prepareContentForWriting(index, todoObject.string); + await prepareContentForWriting(index, todoObject.string); + //event.reply('writeTodoToFile', response); } else { let updatedString: string | null = string; if(state !== undefined && index >= 0) updatedString = await changeCompleteState(string, state) - const response = await writeTodoObjectToFile(index, updatedString); - event.reply('writeTodoToFile', response); + //const response = await prepareContentForWriting(index, updatedString); + await prepareContentForWriting(index, updatedString); + //event.reply('writeTodoToFile', response); } } catch(error: any) { console.error(error); @@ -168,9 +167,9 @@ async function handleCreateFile(event: IpcMainEvent, setDoneFile: boolean): Prom } } -async function handleRemoveLineFromFile(event: IpcMainEvent, index: number): Promise { +function handleRemoveLineFromFile(event: IpcMainEvent, index: number) { try { - await removeLineFromFile(index); + removeLineFromFile(index); } catch (error: any) { console.error(error); event.reply('responseFromMainProcess', error); diff --git a/src/main/modules/Notifications.tsx b/src/main/modules/Notifications.tsx index 5fd11c12..61c5ceab 100644 --- a/src/main/modules/Notifications.tsx +++ b/src/main/modules/Notifications.tsx @@ -1,7 +1,8 @@ import crypto from 'crypto'; import { Notification } from 'electron'; import { config, filter, notifiedTodoObjectsStorage } from '../config'; -import { checkForSearchMatches } from './ProcessDataRequest/ProcessTodoObjects'; +import { createTodoObject } from './ProcessDataRequest/CreateTodoObjects'; +import { checkForSearchMatches } from './Filters/Search'; import dayjs, { Dayjs } from "dayjs"; import isToday from 'dayjs/plugin/isToday'; import isTomorrow from 'dayjs/plugin/isTomorrow'; diff --git a/src/main/modules/ProcessDataRequest/ChangeCompleteState.tsx b/src/main/modules/ProcessDataRequest/ChangeCompleteState.tsx index a75f9282..51bcf565 100644 --- a/src/main/modules/ProcessDataRequest/ChangeCompleteState.tsx +++ b/src/main/modules/ProcessDataRequest/ChangeCompleteState.tsx @@ -2,7 +2,7 @@ import { Item } from 'jstodotxt'; import { createRecurringTodo } from './CreateRecurringTodo'; import restorePreviousPriority from './RestorePreviousPriority'; -async function changeCompleteState(string: string, state: boolean): Promise { +function changeCompleteState(string: string, state: boolean): string { let content = string.replaceAll(/[\x10\r\n]/g, ' [LB] '); @@ -16,7 +16,7 @@ async function changeCompleteState(string: string, state: boolean): Promise item.key === 'rec'); if(recurrence?.value) { - await createRecurringTodo(JsTodoTxtObject.toString(), recurrence.value); + createRecurringTodo(JsTodoTxtObject.toString(), recurrence.value); } const currentPriority = JsTodoTxtObject.priority(); diff --git a/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx b/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx index 143110e1..9e047340 100644 --- a/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx +++ b/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx @@ -1,6 +1,6 @@ import { Item } from 'jstodotxt'; import dayjs from 'dayjs'; -import { writeTodoObjectToFile } from '../File/Write'; +import { prepareContentForWriting } from '../File/Write'; enum RecurrenceInterval { Daily = 'd', @@ -40,7 +40,7 @@ const addRecurrenceToDate = (date: Date, recurrenceInterval: string, recurrenceV } }; -const createRecurringTodo = async (string: string, recurrence: string): Promise => { +const createRecurringTodo = (string: string, recurrence: string): string => { let updatedString = (string || '').replaceAll(/[\x10\r\n]/g, ` ${String.fromCharCode(16)} `); @@ -73,7 +73,6 @@ const createRecurringTodo = async (string: string, recurrence: string): Promise< ? dayjs(newDueDate).subtract(daysBetween, 'day').toDate() : addRecurrenceToDate(dayjs(creationDate).toDate(), recurrenceInterval, recurrenceValue); - // If the user only uses threshold date and no due date, the recurrence should not create a due date: const recurrenceOnlyForThresholdDate = oldThresholdDate && !oldDueDate; if(newDueDate && creationDate && !recurrenceOnlyForThresholdDate) JsTodoTxtObject.setExtension('due', dayjs(newDueDate).format('YYYY-MM-DD')); @@ -82,7 +81,7 @@ const createRecurringTodo = async (string: string, recurrence: string): Promise< JsTodoTxtObject.setComplete(false); JsTodoTxtObject.setCompleted(null); - await writeTodoObjectToFile(-1, JsTodoTxtObject.toString()); + prepareContentForWriting(-1, JsTodoTxtObject.toString()); return 'Recurring todo created'; } diff --git a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx index 0f36625a..f72580e6 100644 --- a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx +++ b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx @@ -5,7 +5,7 @@ import { handleNotification } from '../Notifications'; import { extractSpeakingDates } from '../Date'; import dayjs from 'dayjs'; -let lines: string[]; +let linesInFile: string[]; export const badge: Badge = { count: 0 }; function createTodoObject(index: number, string: string, attributeType?: string, attributeValue?: string): TodoObject { @@ -66,19 +66,19 @@ function createTodoObject(index: number, string: string, attributeType?: string, async function createTodoObjects(fileContent: string | null): Promise { if(!fileContent) { - lines = []; + linesInFile = []; return []; } badge.count = 0; - lines = fileContent.split(/[\r\n]+/).filter(line => line.trim() !== ''); + linesInFile = fileContent.split(/[\r\n]+/).filter(line => line.trim() !== ''); const excludeLinesWithPrefix: string[] = config.get('excludeLinesWithPrefix') || []; - const todoObjects: TodoObject[] = await Promise.all(lines.map(async (line, i) => { + const todoObjects: TodoObject[] = await Promise.all(linesInFile.map(async (line, i) => { if(excludeLinesWithPrefix.some(prefix => line.startsWith(prefix))) { return null; } - const todoObject: TodoObject = await createTodoObject(i, line); + const todoObject: TodoObject = createTodoObject(i, line); if (todoObject.body && !todoObject.complete) { handleNotification(todoObject.due, todoObject.body, badge); @@ -92,4 +92,4 @@ async function createTodoObjects(fileContent: string | null): Promise { if(!showHidden) todoObjects = handleHiddenTodoObjects(todoObjects); - if(filters) todoObjects = applyFilters(todoObjects, filters); + if(filters) todoObjects = applyAttributes(todoObjects, filters); if(searchString) todoObjects = applySearchString(searchString, todoObjects); diff --git a/src/main/modules/ProcessDataRequest/ProcessTodoObjects.tsx b/src/main/modules/ProcessDataRequest/ProcessTodoObjects.tsx index 53cf9800..68f4f6b9 100644 --- a/src/main/modules/ProcessDataRequest/ProcessTodoObjects.tsx +++ b/src/main/modules/ProcessDataRequest/ProcessTodoObjects.tsx @@ -1,9 +1,3 @@ -import dayjs from 'dayjs'; -import * as FilterLang from '../Filters/FilterLang.js'; -import { runQuery } from '../Filters/FilterQuery'; -import { createTodoObject } from './CreateTodoObjects'; -import { config } from '../../config'; - function countTodoObjects(todoObjects: TodoObject[]): HeadersObject { const filteredObjects: TodoObject[] = todoObjects.filter((todoObject: TodoObject) => { return todoObject.visible; @@ -13,77 +7,11 @@ function countTodoObjects(todoObjects: TodoObject[]): HeadersObject { if(todoObject.complete) return todoObject.complete; }); - const headers: HeadersObject = { + return { availableObjects: todoObjects.length, visibleObjects: filteredObjects.length, completedObjects: completedObjects.length - } - - return headers; -} - -function checkForSearchMatches(todoString: string, searchString: string) { - try { - const todoObject = createTodoObject(-1, todoString); - const query = FilterLang.parse(searchString); - return runQuery(todoObject, query); - } catch (error) { - return todoString.toLowerCase().includes(searchString); - } -} - -function applySearchString(searchString: string, todoObjects: TodoObject[]): TodoObject[] { - try { - const query = FilterLang.parse(searchString); - return todoObjects.map(todoObject => { - if(!todoObject.visible) return todoObject; - todoObject.visible = runQuery(todoObject, query); - return todoObject; - }); - } catch (error) { - const lowerSearchString = searchString.toLowerCase(); - return Object.values(todoObjects) - .flat() - .map(todoObject => { - if(!todoObject.visible) return todoObject; - todoObject.visible = todoObject?.string?.toLowerCase().includes(lowerSearchString) || false; - return todoObject; - }) as TodoObject[]; - } -} - -function handleCompletedTodoObjects(todoObjects: TodoObject[]): TodoObject[] { - const showCompleted: boolean = config.get('showCompleted'); - return todoObjects.map((todoObject: TodoObject) => { - if(todoObject.complete && !showCompleted) { - return false; - } else { - return todoObject; - } - }); -} - -function handleHiddenTodoObjects(todoObjects: TodoObject[]): TodoObject[] { - return todoObjects.map((todoObject: TodoObject) => { - if(!todoObject.visible) return todoObject; - todoObject.visible = todoObject.visible && !todoObject.hidden; - return todoObject; - }); -} - -function handleTodoObjectsDates(todoObjects: TodoObject[]): TodoObject[] { - const thresholdDateInTheFuture: boolean = config.get('thresholdDateInTheFuture'); - const dueDateInTheFuture: boolean = config.get('dueDateInTheFuture'); - - return todoObjects.filter((todoObject: TodoObject) => { - if (!todoObject.visible) return true; - - const thresholdDate = dayjs(todoObject?.t); - const dueDate = dayjs(todoObject?.due); - - return !(thresholdDate && thresholdDate.isAfter(dayjs()) && !thresholdDateInTheFuture) && - !(dueDate && dueDate.isAfter(dayjs()) && !dueDateInTheFuture); - }); + }; } function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]): TodoObject[] { @@ -162,12 +90,7 @@ function flattenTodoObjects(todoObjects: TodoObject[], topLevelGroup: string): T } export { - handleHiddenTodoObjects, flattenTodoObjects, sortAndGroupTodoObjects, countTodoObjects, - applySearchString, - handleCompletedTodoObjects, - handleTodoObjectsDates, - checkForSearchMatches, -}; +}; \ No newline at end of file diff --git a/src/main/modules/Tray.tsx b/src/main/modules/Tray.tsx index 8ab61ccd..6e7715b7 100644 --- a/src/main/modules/Tray.tsx +++ b/src/main/modules/Tray.tsx @@ -36,16 +36,14 @@ function createMenuTemplate(files: FileObject[]): Electron.MenuItemConstructorOp } function createTray() { - const isTray = config.get('tray'); - tray?.destroy(); - if(!isTray) { + if(!config.get('tray')) { app.dock?.show(); return; } - const files: FileObject[] = config.get('files') as FileObject[] || []; + const files: FileObject[] = config.get('files'); const iconName: string = process.platform === 'win32' ? 'tray.ico' : 'tray.png'; const menu: Electron.Menu = Menu.buildFromTemplate(createMenuTemplate(files)); diff --git a/src/types.tsx b/src/types.tsx index 6f02ef73..2c242999 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -83,6 +83,7 @@ declare global { useHumanFriendlyDates: boolean; channel: string; chokidarOptions: object; + menuBarVisibility: boolean; __internal__: { migrations: { version: string }}; } @@ -191,12 +192,6 @@ declare global { count: number; }; - // type ElementObject = { - // type: string | null; - // value: string | null; - // index: number; - // }; - interface RequestedData { todoObjects: TodoObject[], attributes: Attributes,