mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
desktop: migrate window state to typescript
This commit is contained in:
committed by
Abdullah Atta
parent
60ba6ba6cf
commit
dde276f77e
@@ -18,36 +18,63 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { JSONStorage } from "../jsonstorage";
|
import { JSONStorage } from "../jsonstorage";
|
||||||
import { screen as _screen, remote } from "electron";
|
import { screen as _screen, BrowserWindow } from "electron";
|
||||||
const screen = _screen || remote.screen;
|
const screen = _screen;
|
||||||
|
|
||||||
class WindowState {
|
type WindowStateOptions = {
|
||||||
constructor(options) {
|
storageKey: string;
|
||||||
this.winRef = null;
|
maximize: boolean;
|
||||||
|
fullScreen: boolean;
|
||||||
|
defaultWidth: number;
|
||||||
|
defaultHeight: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SerializableWindowState = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
displayBounds?: Electron.Rectangle;
|
||||||
|
isMaximized?: boolean;
|
||||||
|
isFullScreen?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WindowState {
|
||||||
|
private readonly config: WindowStateOptions;
|
||||||
|
private state: SerializableWindowState;
|
||||||
|
private windowRef: BrowserWindow | undefined;
|
||||||
|
private readonly eventHandlingDelay = 100;
|
||||||
|
private stateChangeTimer: NodeJS.Timeout | undefined;
|
||||||
|
|
||||||
|
constructor(options?: Partial<WindowStateOptions>) {
|
||||||
|
this.windowRef = undefined;
|
||||||
this.stateChangeTimer = undefined;
|
this.stateChangeTimer = undefined;
|
||||||
this.eventHandlingDelay = 100;
|
|
||||||
this.config = {
|
this.config = {
|
||||||
storageKey: "windowState",
|
storageKey: "windowState",
|
||||||
maximize: true,
|
maximize: true,
|
||||||
fullScreen: true,
|
fullScreen: true,
|
||||||
|
defaultHeight: 800,
|
||||||
|
defaultWidth: 600,
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load previous state
|
// Load previous state
|
||||||
this.state = JSONStorage.get(this.config.storageKey, {});
|
const defaultState: SerializableWindowState = {
|
||||||
|
width: this.config.defaultWidth,
|
||||||
|
height: this.config.defaultHeight,
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
this.state = JSONStorage.get<SerializableWindowState>(
|
||||||
|
this.config.storageKey,
|
||||||
|
defaultState
|
||||||
|
);
|
||||||
|
|
||||||
// Check state validity
|
// Check state validity
|
||||||
this.validateState();
|
this.validateState(defaultState);
|
||||||
|
|
||||||
// Set state fallback values
|
|
||||||
this.state = {
|
|
||||||
width: this.config.defaultWidth || 800,
|
|
||||||
height: this.config.defaultHeight || 600,
|
|
||||||
...this.state
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isNormal(win) {
|
isNormal(win: BrowserWindow) {
|
||||||
return !win.isMaximized() && !win.isMinimized() && !win.isFullScreen();
|
return !win.isMaximized() && !win.isMinimized() && !win.isFullScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +103,9 @@ class WindowState {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
windowWithinBounds(bounds) {
|
windowWithinBounds(bounds: Electron.Rectangle) {
|
||||||
|
if (!this.state) return false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
this.state.x >= bounds.x &&
|
this.state.x >= bounds.x &&
|
||||||
this.state.y >= bounds.y &&
|
this.state.y >= bounds.y &&
|
||||||
@@ -97,12 +126,12 @@ class WindowState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateState() {
|
validateState(defaultState: SerializableWindowState) {
|
||||||
const isValid =
|
const isValid =
|
||||||
this.state &&
|
this.state &&
|
||||||
(this.hasBounds() || this.state.isMaximized || this.state.isFullScreen);
|
(this.hasBounds() || this.state.isMaximized || this.state.isFullScreen);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
this.state = null;
|
this.state = defaultState;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +140,8 @@ class WindowState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState(win) {
|
updateState(win?: BrowserWindow) {
|
||||||
win = win || this.winRef;
|
win = win || this.windowRef;
|
||||||
if (!win) {
|
if (!win) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -133,7 +162,7 @@ class WindowState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveState(win) {
|
saveState(win?: BrowserWindow) {
|
||||||
// Update window state only if it was provided
|
// Update window state only if it was provided
|
||||||
if (win) {
|
if (win) {
|
||||||
this.updateState(win);
|
this.updateState(win);
|
||||||
@@ -145,7 +174,7 @@ class WindowState {
|
|||||||
|
|
||||||
stateChangeHandler = () => {
|
stateChangeHandler = () => {
|
||||||
// Handles both 'resize' and 'move'
|
// Handles both 'resize' and 'move'
|
||||||
clearTimeout(this.stateChangeTimer);
|
if (this.stateChangeTimer) clearTimeout(this.stateChangeTimer);
|
||||||
this.stateChangeTimer = setTimeout(
|
this.stateChangeTimer = setTimeout(
|
||||||
() => this.updateState(),
|
() => this.updateState(),
|
||||||
this.eventHandlingDelay
|
this.eventHandlingDelay
|
||||||
@@ -163,7 +192,7 @@ class WindowState {
|
|||||||
this.saveState();
|
this.saveState();
|
||||||
};
|
};
|
||||||
|
|
||||||
manage(win) {
|
manage(win: BrowserWindow) {
|
||||||
if (this.config.maximize && this.state.isMaximized) {
|
if (this.config.maximize && this.state.isMaximized) {
|
||||||
win.maximize();
|
win.maximize();
|
||||||
}
|
}
|
||||||
@@ -174,17 +203,17 @@ class WindowState {
|
|||||||
win.on("move", this.stateChangeHandler);
|
win.on("move", this.stateChangeHandler);
|
||||||
win.on("close", this.closeHandler);
|
win.on("close", this.closeHandler);
|
||||||
win.on("closed", this.closedHandler);
|
win.on("closed", this.closedHandler);
|
||||||
this.winRef = win;
|
this.windowRef = win;
|
||||||
}
|
}
|
||||||
|
|
||||||
unmanage() {
|
unmanage() {
|
||||||
if (this.winRef) {
|
if (this.windowRef) {
|
||||||
this.winRef.removeListener("resize", this.stateChangeHandler);
|
this.windowRef.removeListener("resize", this.stateChangeHandler);
|
||||||
this.winRef.removeListener("move", this.stateChangeHandler);
|
this.windowRef.removeListener("move", this.stateChangeHandler);
|
||||||
clearTimeout(this.stateChangeTimer);
|
if (this.stateChangeTimer) clearTimeout(this.stateChangeTimer);
|
||||||
this.winRef.removeListener("close", this.closeHandler);
|
this.windowRef.removeListener("close", this.closeHandler);
|
||||||
this.winRef.removeListener("closed", this.closedHandler);
|
this.windowRef.removeListener("closed", this.closedHandler);
|
||||||
this.winRef = null;
|
this.windowRef = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,5 +245,3 @@ class WindowState {
|
|||||||
return this.state.isFullScreen;
|
return this.state.isFullScreen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { WindowState };
|
|
||||||
@@ -27,7 +27,7 @@ import { getBackgroundColor, getTheme, setTheme } from "./config/theme";
|
|||||||
import getZoomFactor from "./ipc/calls/getZoomFactor";
|
import getZoomFactor from "./ipc/calls/getZoomFactor";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import { setupMenu } from "./menu";
|
import { setupMenu } from "./menu";
|
||||||
import { WindowState } from "./config/windowstate";
|
import { WindowState } from "./config/window-state";
|
||||||
import { sendMessageToRenderer } from "./ipc/utils";
|
import { sendMessageToRenderer } from "./ipc/utils";
|
||||||
import { EVENTS } from "./events";
|
import { EVENTS } from "./events";
|
||||||
import "./ipc/index.js";
|
import "./ipc/index.js";
|
||||||
@@ -38,6 +38,7 @@ import yargs from "yargs";
|
|||||||
import { hideBin } from "yargs/helpers";
|
import { hideBin } from "yargs/helpers";
|
||||||
import { getDesktopIntegration } from "./config/desktopIntegration";
|
import { getDesktopIntegration } from "./config/desktopIntegration";
|
||||||
import { AutoLaunch } from "./autolaunch";
|
import { AutoLaunch } from "./autolaunch";
|
||||||
|
import bringToFront from "./ipc/actions/bringToFront";
|
||||||
|
|
||||||
if (!RELEASE) {
|
if (!RELEASE) {
|
||||||
require("electron-reloader")(module);
|
require("electron-reloader")(module);
|
||||||
@@ -251,14 +252,14 @@ function setupTray() {
|
|||||||
label: "Show Notesnook",
|
label: "Show Notesnook",
|
||||||
type: "normal",
|
type: "normal",
|
||||||
icon: APP_ICON_PATH,
|
icon: APP_ICON_PATH,
|
||||||
click: showApp
|
click: bringToFront
|
||||||
},
|
},
|
||||||
{ type: "separator" },
|
{ type: "separator" },
|
||||||
{
|
{
|
||||||
label: "New note",
|
label: "New note",
|
||||||
type: "normal",
|
type: "normal",
|
||||||
click: () => {
|
click: () => {
|
||||||
showApp();
|
bringToFront();
|
||||||
sendMessageToRenderer(EVENTS.createItem, { itemType: "note" });
|
sendMessageToRenderer(EVENTS.createItem, { itemType: "note" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -266,7 +267,7 @@ function setupTray() {
|
|||||||
label: "New notebook",
|
label: "New notebook",
|
||||||
type: "normal",
|
type: "normal",
|
||||||
click: () => {
|
click: () => {
|
||||||
showApp();
|
bringToFront();
|
||||||
sendMessageToRenderer(EVENTS.createItem, { itemType: "notebook" });
|
sendMessageToRenderer(EVENTS.createItem, { itemType: "notebook" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -279,24 +280,12 @@ function setupTray() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
tray.on("double-click", showApp);
|
tray.on("double-click", bringToFront);
|
||||||
tray.on("click", showApp);
|
tray.on("click", bringToFront);
|
||||||
tray.setToolTip("Notesnook");
|
tray.setToolTip("Notesnook");
|
||||||
tray.setContextMenu(contextMenu);
|
tray.setContextMenu(contextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showApp() {
|
|
||||||
if (globalThis.window.isMinimized()) {
|
|
||||||
if (mainWindowState.isMaximized) {
|
|
||||||
globalThis.window.maximize();
|
|
||||||
} else globalThis.window.restore();
|
|
||||||
}
|
|
||||||
globalThis.window.show();
|
|
||||||
globalThis.window.focus();
|
|
||||||
globalThis.window.moveTop();
|
|
||||||
globalThis.window.webContents.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupDesktopIntegration() {
|
function setupDesktopIntegration() {
|
||||||
const desktopIntegration = getDesktopIntegration();
|
const desktopIntegration = getDesktopIntegration();
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,18 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { WindowState } from "../../config/window-state";
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
if (!globalThis.window) return;
|
if (!globalThis.window) return;
|
||||||
|
|
||||||
|
if (globalThis.window.isMinimized()) {
|
||||||
|
if (new WindowState({}).isMaximized) {
|
||||||
|
globalThis.window.maximize();
|
||||||
|
} else globalThis.window.restore();
|
||||||
|
}
|
||||||
globalThis.window.show();
|
globalThis.window.show();
|
||||||
|
globalThis.window.focus();
|
||||||
globalThis.window.moveTop();
|
globalThis.window.moveTop();
|
||||||
|
globalThis.window.webContents.focus();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user