Skip to content

Commit c0c5757

Browse files
committed
refactor: separate redux from store logic
1 parent 58dd247 commit c0c5757

File tree

11 files changed

+143
-223
lines changed

11 files changed

+143
-223
lines changed

fixtures/metadata-dump/tasks.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"pathToMtime": {
3+
"HREN.md": 1745496961167,
4+
"tasks.md": 1752841860573,
5+
"test yaml.md": 1752930178503,
6+
"fixture-vault/Test.md": 1753020632753
7+
},
28
"tasks": [
39
{
410
"symbol": "-",

src/dump-metadata.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ export function createDumpMetadataCommand(app: App) {
2323

2424
await app.vault.adapter.mkdir(metadataDumpPath);
2525

26+
const markdownFiles = app.vault.getMarkdownFiles();
27+
2628
const dump = {
29+
pathToMtime: Object.fromEntries(
30+
markdownFiles.map((it) => [it.path, it.stat.mtime]),
31+
),
2732
tasks: dataview?.pages(`"${fixtureVaultPath}"`).file.tasks.array(),
2833
headings: Object.fromEntries(
2934
app.vault
3035
.getMarkdownFiles()
31-
.map((tFile) => [
32-
tFile.path,
33-
app.metadataCache.getFileCache(tFile)?.headings,
34-
]),
36+
.map((it) => [it.path, app.metadataCache.getFileCache(it)?.headings]),
3537
),
3638
};
3739

src/main.ts

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isAnyOf } from "@reduxjs/toolkit";
12
import {
23
MarkdownView,
34
Notice,
@@ -34,17 +35,15 @@ import {
3435
import {
3536
dataviewChange as dataviewChangeAction,
3637
listPropsParsed,
38+
selectDataviewLoaded,
39+
selectListProps,
3740
} from "./redux/dataview/dataview-slice";
38-
import {
39-
darkModeUpdated,
40-
keyDown as keyDownAction,
41-
networkStatusChanged,
42-
visibleDaysUpdated,
43-
} from "./redux/global-slice";
41+
import { editCanceled, visibleDaysUpdated } from "./redux/global-slice";
4442
import {
4543
initialIcalState,
4644
type IcalState,
4745
icalRefreshRequested,
46+
selectRemoteTasks,
4847
} from "./redux/ical/ical-slice";
4948
import { initListenerMiddleware } from "./redux/listener-middleware";
5049
import { settingsUpdated } from "./redux/settings-slice";
@@ -78,6 +77,7 @@ import { createRenderMarkdown } from "./util/create-render-markdown";
7877
import { createShowPreview } from "./util/create-show-preview";
7978
import { createDailyNoteIfNeeded } from "./util/daily-notes";
8079
import { notifyAboutStartedTasks } from "./util/notify-about-started-tasks";
80+
import { createEnvironmentHooks } from "./util/create-environment-hooks";
8181

8282
export default class DayPlanner extends Plugin {
8383
settings!: () => DayPlannerSettings;
@@ -87,7 +87,6 @@ export default class DayPlanner extends Plugin {
8787
private sTaskEditor!: STaskEditor;
8888
private vaultFacade!: VaultFacade;
8989
private transationWriter!: TransactionWriter;
90-
private syncDataview?: () => void;
9190
private currentUndoNotice?: Notice;
9291

9392
async onload() {
@@ -119,6 +118,14 @@ export default class DayPlanner extends Plugin {
119118
);
120119

121120
this.registerViews({ store, listenerMiddleware });
121+
122+
const handleEditorMenu = createEditorMenuCallback({
123+
sTaskEditor: this.sTaskEditor,
124+
plugin: this,
125+
});
126+
127+
this.registerEvent(this.app.workspace.on("editor-menu", handleEditorMenu));
128+
122129
this.registerCommands();
123130
this.addRibbonIcons();
124131
this.addSettingTab(new DayPlannerSettingsTab(this, this.settingsStore));
@@ -355,9 +362,7 @@ export default class DayPlanner extends Plugin {
355362
onEditCanceled: () => {
356363
new Notice("Edit canceled");
357364

358-
// We need to manually reset tasks to the initial state
359-
// todo: use an optimistic update
360-
this.syncDataview?.();
365+
store.dispatch(editCanceled());
361366
},
362367
});
363368

@@ -371,57 +376,50 @@ export default class DayPlanner extends Plugin {
371376
const useSelector = createUseSelector(store);
372377
const actionDispatched = useActionDispatched({ listenerMiddleware });
373378

379+
const remoteTasks = useSelector(selectRemoteTasks);
380+
const listProps = useSelector(selectListProps);
381+
const dataviewLoaded = useSelector(selectDataviewLoaded);
382+
374383
const dataviewRefreshSignal = derived(
375384
actionDispatched,
376385
($actionDispatched, set) => {
377-
if (listPropsParsed.match($actionDispatched)) {
386+
if (isAnyOf(listPropsParsed, editCanceled)) {
378387
set($actionDispatched);
379388
}
380389
},
381390
);
382391

392+
const { isDarkMode, isOnline, keyDown, isModPressed, layoutReady } =
393+
createEnvironmentHooks({ workspace: this.app.workspace });
394+
383395
const {
384396
editContext,
385397
tasksWithTimeForToday,
386-
dataviewLoaded,
387-
isModPressed,
388398
newlyStartedTasks,
389-
isOnline,
390-
isDarkMode,
391399
dateRanges,
392-
dataviewSyncTrigger,
393400
pointerDateTime,
394401
tasksWithActiveClockProps,
395402
getDisplayedTasksWithClocksForTimeline,
396403
visibleDays,
397404
} = createHooks({
398-
app: this.app,
405+
metadataCache: this.app.metadataCache,
399406
dataviewFacade: this.dataviewFacade,
400407
workspaceFacade: this.workspaceFacade,
401408
settingsStore: this.settingsStore,
402409
onUpdate,
403410
onEditAborted,
404411
currentTime,
405-
dispatch: store.dispatch,
406-
useSelector,
407412
dataviewChange: dataviewRefreshSignal,
413+
remoteTasks,
414+
listProps,
415+
keyDown,
416+
isOnline,
417+
layoutReady,
408418
});
409419

410-
this.syncDataview = () => dataviewSyncTrigger.set({});
411-
412420
this.registerDomEvent(window, "blur", editContext.cancelEdit);
413421
this.registerDomEvent(document, "pointerup", editContext.cancelEdit);
414422

415-
const handleEditorMenu = createEditorMenuCallback({
416-
sTaskEditor: this.sTaskEditor,
417-
plugin: this,
418-
});
419-
420-
this.registerEvent(
421-
// todo: move out
422-
this.app.workspace.on("editor-menu", handleEditorMenu),
423-
);
424-
425423
this.register(
426424
editContext.cursor.subscribe(({ bodyCursor }) => {
427425
document.body.style.cursor = bodyCursor;
@@ -585,21 +583,6 @@ export default class DayPlanner extends Plugin {
585583
}, icalRefreshIntervalMillis),
586584
);
587585

588-
this.registerDomEvent(window, "online", () => {
589-
store.dispatch(networkStatusChanged({ isOnline: true }));
590-
});
591-
this.registerDomEvent(window, "offline", () => {
592-
store.dispatch(networkStatusChanged({ isOnline: false }));
593-
});
594-
this.registerEvent(
595-
this.app.workspace.on("css-change", () => {
596-
store.dispatch(darkModeUpdated(document.body.hasClass("theme-dark")));
597-
}),
598-
);
599-
this.registerDomEvent(document, "keydown", () => {
600-
store.dispatch(keyDownAction());
601-
});
602-
603586
this.registerEvent(
604587
this.app.metadataCache.on(
605588
// @ts-expect-error

src/redux/dataview/dataview-slice.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { STask } from "obsidian-dataview";
44
import { createAppSlice } from "../create-app-slice";
55

66
type LineToListProps = Record<number, unknown>;
7-
type PathToListProps = Record<string, LineToListProps>;
7+
export type PathToListProps = Record<string, LineToListProps>;
88

99
interface DataviewSliceState {
1010
dataviewTasks: Array<STask>;
@@ -51,11 +51,14 @@ export const dataviewSlice = createAppSlice({
5151
selectors: {
5252
selectDataviewTasks: (state) => state.dataviewTasks,
5353
selectListProps: (state) => state.listProps,
54+
selectDataviewLoaded: (state) => state.dataviewLoaded,
5455
},
5556
});
5657

5758
export const { dataviewChange, dataviewTasksUpdated, listPropsParsed } =
5859
dataviewSlice.actions;
59-
export const { selectDataviewTasks, selectListProps } = dataviewSlice.selectors;
60+
61+
export const { selectDataviewTasks, selectListProps, selectDataviewLoaded } =
62+
dataviewSlice.selectors;
6063

6164
export type DataviewChangeAction = ReturnType<typeof dataviewChange>;

src/redux/global-slice.ts

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,104 +3,40 @@ import {
33
createSelector,
44
type PayloadAction,
55
} from "@reduxjs/toolkit";
6-
import ical from "node-ical";
76

87
import { defaultDayFormat } from "../constants";
9-
import type { WithIcalConfig } from "../types";
108

119
import { createAppSlice } from "./create-app-slice";
1210

1311
interface ObsidianSliceState {
14-
icalEvents: Array<WithIcalConfig<ical.VEvent>>;
15-
dateRanges: Record<string, string[]>;
16-
layoutReady: boolean;
17-
isDarkMode: boolean;
18-
modPressed: boolean;
19-
isOnline: boolean;
2012
visibleDays: string[];
2113
}
2214

2315
export const initialState: ObsidianSliceState = {
24-
icalEvents: [],
25-
dateRanges: {},
26-
layoutReady: false,
27-
isDarkMode: false,
28-
modPressed: false,
29-
isOnline: window.navigator.onLine,
30-
// todo: remove after date ranges are migrated to Redux
3116
visibleDays: [],
3217
};
3318

3419
export const globalSlice = createAppSlice({
3520
name: "obsidian",
3621
initialState,
3722
reducers: (create) => ({
38-
icalEventsUpdated: create.reducer(
39-
(
40-
state,
41-
action: PayloadAction<
42-
WithIcalConfig<Array<WithIcalConfig<ical.VEvent>>>
43-
>,
44-
) => {
45-
state.icalEvents = action.payload;
46-
},
47-
),
48-
layoutReady: create.reducer((state) => {
49-
state.layoutReady = true;
50-
}),
51-
darkModeUpdated: create.reducer((state, action: PayloadAction<boolean>) => {
52-
state.isDarkMode = action.payload;
53-
}),
54-
modDown: create.reducer((state) => {
55-
state.modPressed = true;
56-
}),
57-
modUp: create.reducer((state) => {
58-
state.modPressed = false;
59-
}),
60-
networkStatusChanged: create.reducer(
61-
(state, action: PayloadAction<{ isOnline: boolean }>) => {
62-
const { isOnline } = action.payload;
63-
64-
state.isOnline = isOnline;
65-
},
66-
),
67-
dateRangeOpened: create.reducer(
68-
(state, action: PayloadAction<{ id: string; range: string[] }>) => {
69-
const { id, range } = action.payload;
70-
71-
state.dateRanges[id] = range;
72-
},
73-
),
74-
dateRangeClosed: create.reducer((state, action: PayloadAction<string>) => {
75-
delete state.dateRanges[action.payload];
76-
}),
7723
visibleDaysUpdated: create.reducer(
7824
(state, action: PayloadAction<string[]>) => {
7925
state.visibleDays = action.payload;
8026
},
8127
),
28+
editCanceled: () => {},
8229
}),
8330
selectors: {
84-
selectIsOnline: (state) => state.isOnline,
8531
selectVisibleDays: (state) => state.visibleDays,
8632
},
8733
});
8834

8935
export const keyDown = createAction("obsidian/keyDown");
9036

91-
export const {
92-
darkModeUpdated,
93-
layoutReady,
94-
modDown,
95-
modUp,
96-
networkStatusChanged,
97-
icalEventsUpdated,
98-
dateRangeClosed,
99-
dateRangeOpened,
100-
visibleDaysUpdated,
101-
} = globalSlice.actions;
37+
export const { visibleDaysUpdated, editCanceled } = globalSlice.actions;
10238

103-
export const { selectVisibleDays, selectIsOnline } = globalSlice.selectors;
39+
export const { selectVisibleDays } = globalSlice.selectors;
10440

10541
export const selectSortedDedupedVisibleDays = createSelector(
10642
selectVisibleDays,

src/ui/hooks/use-dataview-loaded.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/ui/hooks/use-tasks.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ import type { MetadataCache } from "obsidian";
44
import { derived, type Readable, type Writable } from "svelte/store";
55

66
import { addHorizontalPlacing } from "../../overlap/overlap";
7-
import { selectListProps } from "../../redux/dataview/dataview-slice";
8-
import { selectRemoteTasks } from "../../redux/ical/ical-slice";
9-
import type { createUseSelector } from "../../redux/use-selector";
7+
import { type PathToListProps } from "../../redux/dataview/dataview-slice";
108
import { DataviewFacade } from "../../service/dataview-facade";
119
import { WorkspaceFacade } from "../../service/workspace-facade";
1210
import type { DayPlannerSettings } from "../../settings";
13-
import type { LocalTask, Task, WithTime } from "../../task-types";
11+
import type { LocalTask, RemoteTask, Task, WithTime } from "../../task-types";
1412
import type { OnEditAbortedFn, OnUpdateFn, PointerDateTime } from "../../types";
1513
import { isValidLogEntry } from "../../util/clock";
1614
import * as dv from "../../util/dataview";
@@ -39,8 +37,9 @@ export function useTasks(props: {
3937
onUpdate: OnUpdateFn;
4038
onEditAborted: OnEditAbortedFn;
4139
pointerDateTime: Readable<PointerDateTime>;
42-
useSelector: ReturnType<typeof createUseSelector>;
4340
dataviewChange: Readable<unknown>;
41+
remoteTasks: Readable<RemoteTask[]>;
42+
listProps: Readable<PathToListProps>;
4443
}) {
4544
const {
4645
settingsStore,
@@ -55,12 +54,10 @@ export function useTasks(props: {
5554
dataviewChange,
5655
onUpdate,
5756
onEditAborted,
58-
useSelector,
57+
remoteTasks,
58+
listProps,
5959
} = props;
6060

61-
const remoteTasks = useSelector(selectRemoteTasks);
62-
const listProps = useSelector(selectListProps);
63-
6461
const visibleDailyNotes = useVisibleDailyNotes(
6562
layoutReady,
6663
debouncedTaskUpdateTrigger,

0 commit comments

Comments
 (0)