Skip to content

Commit dc3f156

Browse files
committed
dnd: Add duration dropdown with retoggle logic and updated icon to enabled/disabled visual (slash through it)
Implements a timed DND feature with options like 30m, 1h, etc. Auto-resumes DND state after expiration. DND icon update and modal positioning are pending.
1 parent 15902e5 commit dc3f156

File tree

4 files changed

+99
-9
lines changed

4 files changed

+99
-9
lines changed

app/common/dnd-util.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ type Toggle = {
1818
newSettings: Partial<DndSettings>;
1919
};
2020

21-
export function toggle(): Toggle {
21+
let dndTimeout: NodeJS.Timeout | null = null;
22+
23+
export function toggle(durationInMinutes?: number): Toggle {
2224
const dnd = !ConfigUtil.getConfigItem("dnd", false);
2325
const dndSettingList: SettingName[] = ["showNotification", "silent"];
2426
if (process.platform === "win32") {
@@ -56,5 +58,40 @@ export function toggle(): Toggle {
5658
}
5759

5860
ConfigUtil.setConfigItem("dnd", dnd);
61+
if (dnd && durationInMinutes && !Number.isNaN(durationInMinutes)) {
62+
if (dndTimeout) {
63+
clearTimeout(dndTimeout);
64+
}
65+
66+
dndTimeout = setTimeout(
67+
() => {
68+
toggle(); // Revert DND after timeout
69+
70+
const restoredSettings = ConfigUtil.getConfigItem(
71+
"dndPreviousSettings",
72+
{
73+
showNotification: true,
74+
silent: false,
75+
...(process.platform === "win32" && {
76+
flashTaskbarOnMessage: true,
77+
}),
78+
},
79+
);
80+
81+
if (restoredSettings) {
82+
for (const settingName of dndSettingList) {
83+
ConfigUtil.setConfigItem(
84+
settingName,
85+
restoredSettings[settingName]!,
86+
);
87+
}
88+
}
89+
90+
ConfigUtil.setConfigItem("dnd", false);
91+
},
92+
durationInMinutes * 60 * 1000,
93+
);
94+
}
95+
5996
return {dnd, newSettings};
6097
}

app/common/typed-ipc.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ export type RendererMessage = {
6969
autoHideMenubar: boolean,
7070
updateMenu: boolean,
7171
) => void;
72-
"toggle-dnd": (state: boolean, newSettings: Partial<DndSettings>) => void;
72+
"toggle-dnd": (
73+
state: boolean,
74+
newSettings: Partial<DndSettings>,
75+
duration?: number,
76+
) => void;
7377
"toggle-sidebar": (show: boolean) => void;
7478
"toggle-silent": (state: boolean) => void;
7579
"toggle-tray": (state: boolean) => void;

app/renderer/css/main.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,27 @@ webview.focus {
378378
font-size: 14px;
379379
}
380380

381+
.dropdown {
382+
position: absolute;
383+
left: 60px;
384+
background-color: rgb(44 44 44 / 100%);
385+
border: 1px solid rgb(68 68 68 / 100%);
386+
color: rgb(255 255 255 / 100%);
387+
z-index: 10;
388+
padding: 5px 0;
389+
font-size: 14px;
390+
min-width: 150px;
391+
}
392+
393+
.dropdown div {
394+
padding: 6px 12px;
395+
cursor: pointer;
396+
}
397+
398+
.dropdown div:hover {
399+
background-color: rgb(68 68 68 / 100%);
400+
}
401+
381402
#loading-tooltip::after,
382403
#dnd-tooltip::after,
383404
#back-tooltip::after,

app/renderer/js/main.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -444,14 +444,35 @@ export class ServerManagerView {
444444

445445
initLeftSidebarEvents(): void {
446446
this.$dndButton.addEventListener("click", () => {
447-
const dndUtil = DNDUtil.toggle();
448-
ipcRenderer.send(
449-
"forward-message",
450-
"toggle-dnd",
451-
dndUtil.dnd,
452-
dndUtil.newSettings,
453-
);
447+
const dropdown = document.querySelector("dnd-dropdown");
448+
dropdown?.classList.toggle("hidden");
454449
});
450+
const dropdownItems = document.querySelectorAll("#dnd-dropdown div");
451+
for (const item of dropdownItems) {
452+
item.addEventListener("click", (event) => {
453+
const target = event.target as HTMLElement;
454+
const value = target.dataset.minutes;
455+
const duration = value === "forever" ? undefined : Number(value);
456+
457+
const dndUtil = DNDUtil.toggle(duration);
458+
if (dndUtil.dnd && duration !== undefined) {
459+
console.log(`[DND] Started for ${duration} minutes`);
460+
} else {
461+
console.log("[DND] No timeout set (manual resume)");
462+
}
463+
464+
ipcRenderer.send(
465+
"forward-message",
466+
"toggle-dnd",
467+
dndUtil.dnd,
468+
dndUtil.newSettings,
469+
duration,
470+
);
471+
472+
document.querySelector("dnd-dropdown")?.classList.add("hidden");
473+
});
474+
}
475+
455476
this.$reloadButton.addEventListener("click", async () => {
456477
const tab = this.tabs[this.activeTabIndex];
457478
if (tab instanceof ServerTab) (await tab.webview).reload();
@@ -1210,6 +1231,13 @@ window.addEventListener("load", async () => {
12101231
>${t.__("Do Not Disturb")}</span
12111232
>
12121233
</div>
1234+
<div id="dnd-dropdown" class="dropdown hidden">
1235+
<div data-minutes="1">1 minute</div>
1236+
<div data-minutes="60">1 hour</div>
1237+
<div data-minutes="180">3 hours</div>
1238+
<div data-minutes="720">12 hours</div>
1239+
<div data-minutes="forever">Until I resume</div>
1240+
</div>
12131241
<div class="action-button hidden" id="reload-action">
12141242
<i class="material-icons md-48">refresh</i>
12151243
<span id="reload-tooltip" style="display: none"

0 commit comments

Comments
 (0)