Skip to content

Commit

Permalink
feat: allow user to input shortcuts in the Shortcut component (requir…
Browse files Browse the repository at this point in the history
…es backend changes) (#523)

* feat: allow user to input shortcuts in the Shortcut component

* refactor(renderer): extract tray icon logic to custom hook

* refactor(renderer): use event.key to make code more understandable

* fix(renderer): redo shortcut now ignores Z character casing, it uses the shift key

* chore: update some comments

* refactor: rename close, minimize and show events to reflect better its behaviour
  • Loading branch information
dubisdev authored Dec 30, 2023
1 parent 7e640ff commit 47ecece
Show file tree
Hide file tree
Showing 16 changed files with 157 additions and 107 deletions.
12 changes: 6 additions & 6 deletions app/electron/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import path from "path";
import {
SET_ALWAYS_ON_TOP,
SET_FULLSCREEN_BREAK,
SET_MINIMIZE,
SET_CLOSE,
MINIMIZE_WINDOW,
CLOSE_WINDOW,
SET_UI_THEME,
SET_NATIVE_TITLEBAR,
SET_SHOW,
SHOW_WINDOW,
RELEASE_NOTES_LINK,
TRAY_ICON_UPDATE,
SET_COMPACT_MODE,
Expand Down Expand Up @@ -396,15 +396,15 @@ ipcMain.on(SET_UI_THEME, (e, { isDarkMode }) => {
store.safeSet("isDarkMode", isDarkMode);
});

ipcMain.on(SET_SHOW, () => {
ipcMain.on(SHOW_WINDOW, () => {
if (!win?.isVisible()) {
win?.show();
} else {
win?.focus();
}
});

ipcMain.on(SET_MINIMIZE, (e, { minimizeToTray }) => {
ipcMain.on(MINIMIZE_WINDOW, (e, { minimizeToTray }) => {
if (!minimizeToTray) {
win?.minimize();
} else {
Expand All @@ -415,7 +415,7 @@ ipcMain.on(SET_MINIMIZE, (e, { minimizeToTray }) => {
}
});

ipcMain.on(SET_CLOSE, (e, { closeToTray }) => {
ipcMain.on(CLOSE_WINDOW, (e, { closeToTray }) => {
if (!closeToTray) {
app.exit();
} else {
Expand Down
5 changes: 1 addition & 4 deletions app/renderer/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ const Layout: React.FC<Props> = ({ history, location, children }) => {

const registerKey = useCallback(
(e: KeyboardEvent) => {
const keyCode = e.keyCode;
const keyChar = String.fromCharCode(keyCode);

if (e.altKey && e.shiftKey && keyChar === "T") {
if (e.altKey && e.shiftKey && e.code === "KeyT") {
if (toggleThemeAction) toggleThemeAction();
}
},
Expand Down
22 changes: 19 additions & 3 deletions app/renderer/src/components/Shortcut.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react";
import React, { useState, type KeyboardEvent } from "react";
import {
StyledShortcutWrapper,
StyledShortcutName,
StyledShortcutKey,
} from "styles";
import { getShortcutFromEvent } from "utils/getShortcutFromEvent";

type Props = {
id: string;
Expand All @@ -12,14 +13,29 @@ type Props = {
};

const Shortcut: React.FC<Props> = ({ id, name, shortcutKey }) => {
const [shortcut, setShortcut] = useState(() => shortcutKey);

const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
const shortcut = getShortcutFromEvent(e);

if (shortcut) {
console.log(shortcut);

// For now we don't update the UI, as it is not being saved
// TODO: Uncomment when we have a way to save the shortcuts
// setShortcut(shortcut);
}
};

return (
<StyledShortcutWrapper>
<StyledShortcutName htmlFor={id}>{name}</StyledShortcutName>
<StyledShortcutKey
type="text"
value={shortcutKey}
value={shortcut}
id={id}
disabled
onKeyDown={handleKeyDown}
readOnly
/>
</StyledShortcutWrapper>
);
Expand Down
47 changes: 11 additions & 36 deletions app/renderer/src/contexts/connectors/ElectronConnector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@ import { AppStateTypes, SettingTypes } from "../../store";
import { CounterContext } from "../CounterContext";
import {
SET_ALWAYS_ON_TOP,
SET_CLOSE,
CLOSE_WINDOW,
SET_COMPACT_MODE,
SET_FULLSCREEN_BREAK,
SET_MINIMIZE,
MINIMIZE_WINDOW,
SET_NATIVE_TITLEBAR,
SET_SHOW,
SHOW_WINDOW,
SET_UI_THEME,
TRAY_ICON_UPDATE,
SET_OPEN_AT_LOGIN,
} from "@pomatez/shareables";
import { encodeSvg } from "../../utils";
import { TraySVG } from "../../components";
import { InvokeConnector } from "../InvokeConnector";
import { useTrayIconUpdates } from "hooks/useTrayIconUpdates";

export const ElectronInvokeConnector: InvokeConnector = {
send: (event: string, ...payload: any) => {
Expand All @@ -30,26 +29,22 @@ export const ElectronInvokeConnector: InvokeConnector = {
export const ElectronConnectorProvider: React.FC = ({ children }) => {
const { electron } = window;

// TODO do logic to switch out the connectors based on the platform

const timer = useSelector((state: AppStateTypes) => state.timer);

const settings: SettingTypes = useSelector(
(state: AppStateTypes) => state.settings
);

const { count, duration, timerType, shouldFullscreen } =
useContext(CounterContext);
const dashOffset = (duration - count) * (24 / duration);
const { shouldFullscreen } = useContext(CounterContext);

const onMinimizeCallback = useCallback(() => {
electron.send(SET_MINIMIZE, {
electron.send(MINIMIZE_WINDOW, {
minimizeToTray: settings.minimizeToTray,
});
}, [electron, settings.minimizeToTray]);

const onExitCallback = useCallback(() => {
electron.send(SET_CLOSE, {
electron.send(CLOSE_WINDOW, {
closeToTray: settings.closeToTray,
});
}, [electron, settings.closeToTray]);
Expand All @@ -70,7 +65,7 @@ export const ElectronConnectorProvider: React.FC = ({ children }) => {

useEffect(() => {
if (!settings.enableFullscreenBreak) {
electron.send(SET_SHOW);
electron.send(SHOW_WINDOW);
}
}, [electron, timer.timerType, settings.enableFullscreenBreak]);

Expand Down Expand Up @@ -111,29 +106,9 @@ export const ElectronConnectorProvider: React.FC = ({ children }) => {
});
}, [electron, settings.openAtLogin]);

useEffect(() => {
if (timer.playing) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = 16;
canvas.height = 16;

let svgXML = encodeSvg(
<TraySVG timerType={timerType} dashOffset={dashOffset} />
);

const img = new Image();
img.src = svgXML;

img.onload = function () {
ctx?.drawImage(img, 0, 0);
const dataUrl = canvas.toDataURL("image/png");

electron.send(TRAY_ICON_UPDATE, dataUrl);
};
}
}, [electron, timer.playing, timerType, dashOffset]);
useTrayIconUpdates((dataUrl) => {
electron.send(TRAY_ICON_UPDATE, { dataUrl });
});

return (
<ConnnectorContext.Provider
Expand Down
52 changes: 14 additions & 38 deletions app/renderer/src/contexts/connectors/TauriConnector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import { CounterContext } from "../CounterContext";
import {
CHECK_FOR_UPDATES,
SET_ALWAYS_ON_TOP,
SET_CLOSE,
CLOSE_WINDOW,
SET_COMPACT_MODE,
SET_FULLSCREEN_BREAK,
SET_MINIMIZE,
MINIMIZE_WINDOW,
SET_NATIVE_TITLEBAR,
SET_SHOW,
SHOW_WINDOW,
SET_UI_THEME,
TRAY_ICON_UPDATE,
UPDATE_AVAILABLE,
} from "@pomatez/shareables";
import { encodeSvg } from "../../utils";
import { TraySVG } from "../../components";
import {
enable,
disable,
Expand All @@ -27,6 +25,7 @@ import { invoke } from "@tauri-apps/api/primitives";
import { listen } from "@tauri-apps/api/event";
import { open } from "@tauri-apps/plugin-shell";
import { setUpdateBody, setUpdateVersion } from "../../store/update";
import { useTrayIconUpdates } from "hooks/useTrayIconUpdates";

export const TauriInvokeConnector = {
send: (event: string, ...payload: any) => {
Expand All @@ -43,11 +42,12 @@ export const TauriConnectorProvider: React.FC = ({ children }) => {
(state: AppStateTypes) => state.settings
);

// Prevent webpage behavior (naitive apps shouldn't refresh with F5 or Ctrl+R)
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
if (
(event.ctrlKey && (event.key === "r" || event.key === "R")) ||
event.key === "F5"
(event.ctrlKey && event.code === "KeyR") ||
event.code === "F5"
) {
event.preventDefault();
}
Expand Down Expand Up @@ -114,23 +114,19 @@ export const TauriConnectorProvider: React.FC = ({ children }) => {
});
}, [settings.openAtLogin]);

// TODO do logic to switch out the connectors based on the platform

const timer = useSelector((state: AppStateTypes) => state.timer);

const { count, duration, timerType, shouldFullscreen } =
useContext(CounterContext);
const dashOffset = (duration - count) * (24 / duration);
const { shouldFullscreen } = useContext(CounterContext);

const onMinimizeCallback = useCallback(() => {
send(SET_MINIMIZE, {
send(MINIMIZE_WINDOW, {
minimizeToTray: settings.minimizeToTray,
});
console.log("Minimize callback");
}, [send, settings.minimizeToTray]);

const onExitCallback = useCallback(() => {
send(SET_CLOSE, {
send(CLOSE_WINDOW, {
closeToTray: settings.closeToTray,
});
}, [send, settings.closeToTray]);
Expand All @@ -142,7 +138,7 @@ export const TauriConnectorProvider: React.FC = ({ children }) => {

useEffect(() => {
if (!settings.enableFullscreenBreak) {
send(SET_SHOW);
send(SHOW_WINDOW);
}
}, [send, timer.timerType, settings.enableFullscreenBreak]);

Expand Down Expand Up @@ -177,29 +173,9 @@ export const TauriConnectorProvider: React.FC = ({ children }) => {
});
}, [send, settings.useNativeTitlebar]);

useEffect(() => {
if (timer.playing) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = 16;
canvas.height = 16;

let svgXML = encodeSvg(
<TraySVG timerType={timerType} dashOffset={dashOffset} />
);

const img = new Image();
img.src = svgXML;

img.onload = function () {
ctx?.drawImage(img, 0, 0);
const dataUrl = canvas.toDataURL("image/png");

send(TRAY_ICON_UPDATE, { dataUrl });
};
}
}, [send, timer.playing, timerType, dashOffset]);
useTrayIconUpdates((dataUrl) => {
send(TRAY_ICON_UPDATE, { dataUrl });
});

// Workaround to make sure it only calls once on mount
const checkUpdate = useCallback(() => {
Expand Down
2 changes: 1 addition & 1 deletion app/renderer/src/hooks/useTargetOutside.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const useTargetOutside = ({ ref, eventType }: TargetOutside) => {
}

function closeOnEscape(e: KeyboardEvent) {
if (e.keyCode === 27) {
if (e.code === "Escape") {
setState(false);
}
}
Expand Down
39 changes: 39 additions & 0 deletions app/renderer/src/hooks/useTrayIconUpdates.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CounterContext } from "contexts";
import { useEffect, useContext } from "react";
import { useSelector } from "react-redux";
import type { AppStateTypes } from "store";
import { TraySVG } from "components";
import { encodeSvg } from "utils";

export const useTrayIconUpdates = (
onNewIcon: (dataUrl: string) => void
) => {
const timer = useSelector((state: AppStateTypes) => state.timer);

const { count, duration, timerType } = useContext(CounterContext);
const dashOffset = (duration - count) * (24 / duration);

useEffect(() => {
if (timer.playing) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = 16;
canvas.height = 16;

let svgXML = encodeSvg(
<TraySVG timerType={timerType} dashOffset={dashOffset} />
);

const img = new Image();
img.src = svgXML;

img.onload = function () {
ctx?.drawImage(img, 0, 0);
const dataUrl = canvas.toDataURL("image/png");

onNewIcon(dataUrl);
};
}
}, [onNewIcon, timer.playing, timerType, dashOffset]);
};
4 changes: 2 additions & 2 deletions app/renderer/src/routes/Config/SpecialField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const SpecialField: React.FC<Props> = ({

useEffect(() => {
function registerEscape(e: KeyboardEvent) {
if (e.keyCode === 27) {
if (e.code === "Escape") {
setShowSetter(false);
}
}
Expand All @@ -161,7 +161,7 @@ const SpecialField: React.FC<Props> = ({
}
}}
onKeyDown={(e) => {
if (e.keyCode === 13) {
if (e.key === "Enter") {
setShowSetter(true);
}
}}
Expand Down
2 changes: 1 addition & 1 deletion app/renderer/src/routes/Tasks/TaskDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const TaskDetails = React.forwardRef<HTMLDivElement, Props>(

useEffect(() => {
function registerEscape(e: KeyboardEvent) {
if (e.keyCode === 27) {
if (e.key === "Escape") {
if (onExit) {
onExit();
}
Expand Down
2 changes: 1 addition & 1 deletion app/renderer/src/routes/Tasks/TaskHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const TaskHeader: React.FC<Props> = ({
};

inputRef.current.onkeyup = (e: KeyboardEvent) => {
if (e.keyCode === 13 || e.keyCode === 10) {
if (e.key === "Enter" || e.keyCode === 10) {
if (inputRef.current) {
if (onEditTitle && inputRef.current.value) {
onEditTitle(inputRef.current.value);
Expand Down
Loading

0 comments on commit 47ecece

Please sign in to comment.