From 6ffec3065a7f293d614e1f7ddd9da071e6ff3a72 Mon Sep 17 00:00:00 2001 From: ransome1 Date: Wed, 13 Sep 2023 18:05:41 +0200 Subject: [PATCH] Fixed line break issue on Windows, refactored some CSS, added icons to splash screens, added keyboard shortcut to toggle settings --- release/app/package.json | 2 +- src/__tests__/__mock__/recurrence.txt | 10 ++--- src/__tests__/__mock__/test.txt | 2 +- src/main/config.ts | 3 +- src/main/menu.ts | 25 ++++++++++++- src/main/modules/CreateTodoObjects.ts | 3 +- src/main/modules/Ipc.ts | 3 +- src/main/modules/ProcessTodoObjects.ts | 6 +-- src/main/preload.ts | 4 +- src/renderer/App.tsx | 52 ++++++++++++++++---------- src/renderer/Navigation.js | 17 +++------ src/renderer/RecurrencePicker.scss | 2 + src/renderer/Search.scss | 2 +- src/renderer/SplashScreen.js | 8 ++-- src/renderer/SplashScreen.scss | 9 ++++- 15 files changed, 94 insertions(+), 54 deletions(-) diff --git a/release/app/package.json b/release/app/package.json index fe773f9d..b65718b0 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -1,6 +1,6 @@ { "name": "sleek", - "version": "2.0.0-dev9", + "version": "2.0.0-dev10", "description": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)", "synopsis": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)", "keywords": [ diff --git a/src/__tests__/__mock__/recurrence.txt b/src/__tests__/__mock__/recurrence.txt index f21077c6..2d8998e2 100644 --- a/src/__tests__/__mock__/recurrence.txt +++ b/src/__tests__/__mock__/recurrence.txt @@ -1,7 +1,7 @@ -2023-09-12 Line 1 rec:1d due:2023-09-13 -2023-09-12 Line 1 rec:w due:2023-09-19 -2023-09-12 Line 1 rec:2m due:2023-11-12 -2023-09-12 Line 1 rec:+1d due:2023-09-14 -2023-09-12 Line 1 rec:7w due:2023-10-31 +2023-09-13 Line 1 rec:1d due:2023-09-14 +2023-09-13 Line 1 rec:w due:2023-09-20 +2023-09-13 Line 1 rec:2m due:2023-11-13 +2023-09-13 Line 1 rec:+1d due:2023-09-15 +2023-09-13 Line 1 rec:7w due:2023-11-01 2023-07-21 Line 1 rec:+1b due:2023-07-24 \ No newline at end of file diff --git a/src/__tests__/__mock__/test.txt b/src/__tests__/__mock__/test.txt index afc7a955..ce811c3b 100644 --- a/src/__tests__/__mock__/test.txt +++ b/src/__tests__/__mock__/test.txt @@ -1,5 +1,5 @@ Line 1 Edited line New line -2023-09-12 New line with creation date +2023-09-13 New line with creation date New line with relative threshold date t:June 3rd, 2005 \ No newline at end of file diff --git a/src/main/config.ts b/src/main/config.ts index 31d5a4ea..76ded9fe 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -41,6 +41,7 @@ const defaultConfigData = { shouldUseDarkColors: false, notificationsAllowed: true, showFileTabs: true, + isNavigationOpen: true, }; const userDataDirectory = path.join(app.getPath('userData'), 'userData' + app.getVersion()); @@ -75,7 +76,7 @@ filterStorage.onDidChange('filters' as never, async () => { mainWindow!.webContents.send('requestData', todoObjects, attributes, headers, filters); }); -configStorage.onDidChange('files', (files: File[] | undefined) => { +configStorage.onDidChange('files', async (files: File[] | undefined) => { if (files) { buildMenu(files); mainWindow!.webContents.send('updateFiles', files); diff --git a/src/main/menu.ts b/src/main/menu.ts index b83d2bb1..c9921ffb 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -30,6 +30,14 @@ function buildMenu(files: File[]) { dialog.showMessageBox(options); }, }, + { + label: 'Settings', + accelerator: 'CmdOrCtrl+.', + click: () => { + mainWindow!.webContents.send('setIsSettingsOpen'); + }, + }, + { type: 'separator' }, { label: 'Hide', accelerator: isMac ? 'Cmd+H' : 'Win+D', @@ -91,14 +99,27 @@ function buildMenu(files: File[]) { }, { label: 'View', - submenu: [ + submenu: [ + { + label: 'Toggle drawer', + accelerator: 'CmdOrCtrl+B', + click: () => { + mainWindow!.webContents.send('setIsDrawerOpen'); + }, + }, { label: 'Toggle navigation', accelerator: 'Ctrl+Alt+H', click: () => { - mainWindow!.webContents.send('setIsNavigationHidden'); + mainWindow!.webContents.send('setIsNavigationOpen'); }, }, + { + label: 'Toggle file tabs', + click: () => { + mainWindow!.webContents.send('setShowFileTabs'); + }, + }, ], }, { diff --git a/src/main/modules/CreateTodoObjects.ts b/src/main/modules/CreateTodoObjects.ts index f8254451..7c93ee26 100644 --- a/src/main/modules/CreateTodoObjects.ts +++ b/src/main/modules/CreateTodoObjects.ts @@ -3,11 +3,12 @@ import { handleNotification } from './HandleNotification'; import { TodoObject, DateAttributes } from '../util'; import { extractSpeakingDates } from './Date'; import dayjs from 'dayjs'; +import os from 'os'; let lines: string[]; function createTodoObjects(fileContent: string): TodoObject[] { - lines = fileContent.split('\n'); + lines = fileContent.split(os.EOL); const todoObjects: TodoObject[] = lines .map((line, i) => { try { diff --git a/src/main/modules/Ipc.ts b/src/main/modules/Ipc.ts index 6124b129..6c182b59 100644 --- a/src/main/modules/Ipc.ts +++ b/src/main/modules/Ipc.ts @@ -15,11 +15,9 @@ async function handleDataRequest(event: IpcMainEvent, searchString: string): voi async function handleWriteTodoToFile(event: IpcMainEvent, id: number, string: string, state: boolean | undefined, remove: boolean): Promise { try { let updatedString: string = string; - if (state !== undefined && id >= 0 && !remove) { updatedString = await changeCompleteState(string, state); } - writeTodoObjectToFile(id, updatedString, remove).then(function (response) { console.log('ipcEvents.ts:', response); }).catch((error) => { @@ -41,6 +39,7 @@ function handleStoreGetConfig(event: IpcMainEvent, value: string): void { function handleStoreSetConfig(event: IpcMainEvent, key: string, value: any): void { try { + if(!key) return false; configStorage.set(key, value); console.log(`ipcEvents.ts: Set ${key} to ${value}`); } catch (error) { diff --git a/src/main/modules/ProcessTodoObjects.ts b/src/main/modules/ProcessTodoObjects.ts index 067c7a0e..0dc6b498 100644 --- a/src/main/modules/ProcessTodoObjects.ts +++ b/src/main/modules/ProcessTodoObjects.ts @@ -82,7 +82,7 @@ function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]): return grouped; } - function sortAndGroupObjects(objects: any[], sortIndex: number): any { + function sortAndGroupObjects(objects: any[], sortIndex: number, sorting: Sorting[]): any { if (sortIndex >= sorting.length) { return objects; } @@ -98,13 +98,13 @@ function sortAndGroupTodoObjects(todoObjects: TodoObject[], sorting: Sorting[]): const sortedGroups: { [key: string]: any } = {}; for (const key of sortedKeys) { - sortedGroups[key] = sortAndGroupObjects(grouped[key], sortIndex + 1); + sortedGroups[key] = sortAndGroupObjects(grouped[key], sortIndex + 1, sorting); } return sortedGroups; } const sortedTodoObjects = Object.values(todoObjects).sort(sortObjectsBySorting); - const sortedAndGrouped = sortAndGroupObjects(sortedTodoObjects, 0); + const sortedAndGrouped = sortAndGroupObjects(sortedTodoObjects, 0, sorting); return sortedAndGrouped; } diff --git a/src/main/preload.ts b/src/main/preload.ts index f84e9812..7e55ee48 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -12,7 +12,9 @@ export type Channels = | 'storeSetConfig' | 'storeSetFilters' | 'archiveTodos' - | 'shouldUseDarkColors'; + | 'setIsNavigationOpen' + | 'setShowFileTabs' + | 'setIsSettingsOpen'; interface ElectronStore { get: (key: string) => T; diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index fb08bea3..351a778b 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -11,6 +11,7 @@ import Search from './Search'; import TodoDialog from './TodoDialog'; import ArchiveTodos from './ArchiveTodos'; import ToolBar from './ToolBar'; +import { Sorting } from '../main/util'; import './App.scss'; const ipcRenderer = window.electron.ipcRenderer; @@ -21,25 +22,24 @@ const App = () => { const [isDrawerOpen, setIsDrawerOpen] = useState(store.get('isDrawerOpen') || false); const [isSearchOpen, setIsSearchOpen] = useState(store.get('isSearchOpen') || false); const [splashScreen, setSplashScreen] = useState(null); - const [drawerParameter, setDrawerParameter] = useState(); const [snackBarOpen, setSnackBarOpen] = useState(false); - const [fileTabs, setFileTabs] = useState(true); const [snackBarContent, setSnackBarContent] = useState(null); const [snackBarSeverity, setSnackBarSeverity] = useState(null); const [dialogOpen, setDialogOpen] = useState(false); - const [todoObject, setTodoObject] = useState(null); const [searchString, setSearchString] = useState(null); const [todoObjects, setTodoObjects] = useState(null); + const [todoObject, setTodoObject] = useState(null); const [headers, setHeaders] = useState(null); const [filters, setFilters] = useState({}); const [attributes, setAttributes] = useState({}); const [textFieldValue, setTextFieldValue] = useState(''); - const [sorting, setSorting] = useState(store.get('sorting') || null); + const [sorting, setSorting] = useState(store.get('sorting') || null); const searchFieldRef = useRef(null); - const [isNavigationHidden, setIsNavigationHidden] = useState(store.get('isNavigationHidden') || false); + const [isNavigationOpen, setIsNavigationOpen] = useState(store.get('isNavigationOpen')); const [colorTheme, setColorTheme] = useState(store.get('colorTheme') || 'system'); const [shouldUseDarkColors, setShouldUseDarkColors] = useState(store.get('shouldUseDarkColors') || false); const [showFileTabs, setShowFileTabs] = useState(store.get('showFileTabs')); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); const responseHandler = function(response) { if (response instanceof Error) { @@ -62,7 +62,7 @@ const App = () => { }; const handleUpdateFiles = (files: object) => { - setFiles(files) + setFiles(files); }; const handleUpdateSorting = (sorting: object) => { @@ -73,17 +73,25 @@ const App = () => { setIsSearchOpen(prevIsSearchOpen => !prevIsSearchOpen); }; - const handleSetIsNavigationHidden = () => { - setIsNavigationHidden(prevIsNavigationHidden => !prevIsNavigationHidden); + const handleSetIsNavigationOpen = () => { + setIsNavigationOpen(prevIsNavigationOpen => !prevIsNavigationOpen); }; const handleSetShouldUseDarkColors = (shouldUseDarkColors: boolean) => { setShouldUseDarkColors(shouldUseDarkColors); }; - useEffect(() => { - store.set('isNavigationHidden', isNavigationHidden) - }, [isNavigationHidden]); + const handleSetShowFileTabs = () => { + setShowFileTabs(prevShowFileTabs => !prevShowFileTabs); + }; + + const handleSetIsDrawerOpen = () => { + setIsDrawerOpen(prevIsDrawerOpen => !prevIsDrawerOpen); + }; + + const handleSetIsSettingsOpen = () => { + setIsSettingsOpen(prevIsSettingsOpen => !prevIsSettingsOpen); + }; useEffect(() => { if(!headers) return; @@ -119,6 +127,10 @@ const App = () => { store.set('isSearchOpen', isSearchOpen) }, [isSearchOpen]); + useEffect(() => { + store.set('', isNavigationOpen) + }, [isNavigationOpen]); + useEffect(() => { if(!snackBarContent) return; setSnackBarOpen(true); @@ -137,33 +149,35 @@ const App = () => { ipcRenderer.on('updateFiles', handleUpdateFiles); ipcRenderer.on('updateSorting', handleUpdateSorting); ipcRenderer.on('setIsSearchOpen', handleSetIsSearchOpen); - ipcRenderer.on('setIsNavigationHidden', handleSetIsNavigationHidden); - ipcRenderer.on('shouldUseDarkColors', handleSetShouldUseDarkColors); + ipcRenderer.on('setIsNavigationOpen', handleSetIsNavigationOpen); + ipcRenderer.on('setShouldUseDarkColors', handleSetShouldUseDarkColors); + ipcRenderer.on('setShowFileTabs', handleSetShowFileTabs); + ipcRenderer.on('setIsDrawerOpen', handleSetIsDrawerOpen); + ipcRenderer.on('setIsSettingsOpen', handleSetIsSettingsOpen); }, []); return ( -
+
{ - const [isSettingsOpen, setIsSettingsOpen] = useState(false); - +const NavigationComponent = ({ isSettingsOpen, setIsSettingsOpen, isDrawerOpen, setIsDrawerOpen, setDialogOpen, files, headers, isNavigationOpen, setIsNavigationOpen, colorTheme, setColorTheme, showFileTabs, setShowFileTabs }) => { const openSettings = () => { setIsSettingsOpen(true); }; @@ -20,15 +18,14 @@ const NavigationComponent = ({ isDrawerOpen, setIsDrawerOpen, drawerParameter, s const handleButtonClicked = (parameter) => { setIsDrawerOpen(prevIsDrawerOpen => !prevIsDrawerOpen) - setDrawerParameter(parameter) }; const handleOpenFile = () => { ipcRenderer.send('openFile'); }; - const hideNavigation = () => { - setIsNavigationHidden(prevIsNavigationHidden => !prevIsNavigationHidden); + const toggleNavigation = () => { + setIsNavigationOpen(prevIsNavigationOpen => !prevIsNavigationOpen); }; useEffect(() => { @@ -37,10 +34,6 @@ const NavigationComponent = ({ isDrawerOpen, setIsDrawerOpen, drawerParameter, s setDialogOpen(true); return; } - if ((event.metaKey || event.ctrlKey) && event.key === 'b') { - setIsDrawerOpen((prevIsDrawerOpen) => !prevIsDrawerOpen); - return; - } }; document.addEventListener('keydown', handleKeyDown); return () => { @@ -76,11 +69,11 @@ const NavigationComponent = ({ isDrawerOpen, setIsDrawerOpen, drawerParameter, s showFileTabs={showFileTabs} setShowFileTabs={setShowFileTabs} /> - - diff --git a/src/renderer/RecurrencePicker.scss b/src/renderer/RecurrencePicker.scss index f2e3b77e..aab965f0 100644 --- a/src/renderer/RecurrencePicker.scss +++ b/src/renderer/RecurrencePicker.scss @@ -1,5 +1,7 @@ #recurrencePicker { + .MuiPaper-root { + padding: 1em; .MuiFormControl-root { margin-right: 1em; vertical-align: middle; diff --git a/src/renderer/Search.scss b/src/renderer/Search.scss index ed4c0148..d38b23cc 100644 --- a/src/renderer/Search.scss +++ b/src/renderer/Search.scss @@ -4,7 +4,7 @@ height: 2.5em; min-height: 2.5em; display: flex; - flex: 1; + padding-right: 2.5em; .MuiTextField-root { height: 100%; flex-direction: row; diff --git a/src/renderer/SplashScreen.js b/src/renderer/SplashScreen.js index 429fccc2..50b70794 100644 --- a/src/renderer/SplashScreen.js +++ b/src/renderer/SplashScreen.js @@ -1,5 +1,7 @@ import React from 'react'; import { Button, Box } from '@mui/material'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGhost, faHippo, faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import './SplashScreen.scss'; const ipcRenderer = window.electron.ipcRenderer; @@ -30,7 +32,7 @@ const SplashScreen = ({ screen, setSearchString, setDialogOpen }) => { {screen === 'noTodosVisible' && ( <> -

No todos found

+

No results found for either your search input nor your selected filters