Skip to content

Commit

Permalink
Added shortcuts plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverschwendener committed Jan 30, 2019
1 parent 3a453ba commit 2d04320
Show file tree
Hide file tree
Showing 29 changed files with 522 additions and 102 deletions.
2 changes: 1 addition & 1 deletion main.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<title>ueli</title>
</head>
<body>
<div id="app" @keydown="onKeypress">
<div id="app" @keydown="onKeyPress">
<user-styles :config="config.appearanceOptions"></user-styles>
<user-input></user-input>
<search-results></search-results>
Expand Down
6 changes: 6 additions & 0 deletions src/common/config/default-shortcuts-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ShortcutsOptions } from "./shortcuts-options";

export const defaultShortcutsOptions: ShortcutsOptions = {
isEnabled: true,
shortcuts: [],
};
2 changes: 2 additions & 0 deletions src/common/config/default-user-config-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { defaultApplicationSearchOptions } from "../../main/plugins/application-
import { defaultGeneralOptions } from "./default-general-options";
import { defaultSearchEngineOptions } from "./default-search-engine-options";
import { defaultAppearanceOptions } from "./default-appearance-options";
import { defaultShortcutsOptions } from "./default-shortcuts-options";

export const defaultUserConfigOptions: UserConfigOptions = {
appearanceOptions: defaultAppearanceOptions,
applicationSearchOptions: defaultApplicationSearchOptions,
generalOptions: defaultGeneralOptions,
searchEngineOptions: defaultSearchEngineOptions,
shortcutsOptions: defaultShortcutsOptions,
};
6 changes: 6 additions & 0 deletions src/common/config/shortcuts-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Shortcut } from "../../main/plugins/shorcuts-plugin/shortcut";

export interface ShortcutsOptions {
isEnabled: boolean;
shortcuts: Shortcut[];
}
2 changes: 2 additions & 0 deletions src/common/config/user-config-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { ApplicationSearchOptions } from "../../main/plugins/application-search-
import { GeneralOptions } from "./general-options";
import { SearchEngineOptions } from "./search-engine-options";
import { AppearanceOptions } from "./appearance-options";
import { ShortcutsOptions } from "./shortcuts-options";

export interface UserConfigOptions {
appearanceOptions: AppearanceOptions;
applicationSearchOptions: ApplicationSearchOptions;
searchEngineOptions: SearchEngineOptions;
shortcutsOptions: ShortcutsOptions;
generalOptions: GeneralOptions;
}
4 changes: 0 additions & 4 deletions src/common/icon-type.ts

This file was deleted.

7 changes: 7 additions & 0 deletions src/common/icon/icon-type-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IconType } from "./icon-type";

export class IconTypeHelpers {
public static isValidIconType(iconType: IconType): boolean {
return Object.values(IconType).find((i) => i === iconType) !== undefined;
}
}
4 changes: 4 additions & 0 deletions src/common/icon/icon-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum IconType {
URL = "URL",
SVG = "SVG",
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/common/search-result-item.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PluginType } from "../main/plugin-type";
import { Icon } from "./icon";
import { Icon } from "./icon/icon";

export interface SearchResultItem {
description: string;
Expand Down
2 changes: 1 addition & 1 deletion src/main/helpers/file-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class FileHelpers {
}

public static fileExists(filePath: string): Promise<boolean> {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
exists(filePath, (fileExists) => {
resolve(fileExists);
});
Expand Down
157 changes: 82 additions & 75 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,26 @@ const logger = new ConsoleLogger();
const configRepository = new ElectronStoreConfigRepository(defaultUserConfigOptions);
const currentOperatingSystem = platform() === "darwin" ? OperatingSystem.macOS : OperatingSystem.Windows;

if (currentOperatingSystem === OperatingSystem.macOS) {
app.dock.hide();
}

let mainWindow: BrowserWindow;
let settingsWindow: BrowserWindow;

let config = configRepository.getConfig();
let searchEngine = currentOperatingSystem === OperatingSystem.macOS ? getMacOsProductionSearchEngine(config) : getWindowsProductionSearchEngine(config);

const notifyRenderer = (ipcChannel: IpcChannels, message?: string) => {
function notifyRenderer(ipcChannel: IpcChannels, message?: string) {
const allWindows = [mainWindow, settingsWindow];
allWindows.forEach((window) => {
if (window !== undefined && !window.isDestroyed()) {
window.webContents.send(ipcChannel, message);
}
});
};
}

const refreshAllIndexes = () => {
function refreshAllIndexes() {
searchEngine.refreshIndexes()
.then(() => {
const message = "Successfully refreshed indexes";
Expand All @@ -44,42 +48,42 @@ const refreshAllIndexes = () => {
logger.error(err);
notifyRenderer(IpcChannels.indexRefreshFailed, err);
});
};
}

let rescanInterval = setInterval(() => refreshAllIndexes(), Number(config.generalOptions.rescanIntervalInSeconds) * 1000);

const registerGlobalKeyboardShortcut = (toggleAction: () => void, hotKey: string) => {
function registerGlobalKeyboardShortcut(toggleAction: () => void, hotKey: string) {
globalShortcut.unregisterAll();
globalShortcut.register(hotKey, toggleAction);
};
}

const showMainWindow = () => {
function showMainWindow() {
mainWindow.show();
mainWindow.webContents.send(IpcChannels.mainWindowHasBeenShown);
};
}

const hideMainWindow = () => {
function hideMainWindow() {
mainWindow.webContents.send(IpcChannels.mainWindowHasBeenHidden);

setTimeout(() => {
updateMainWindowSize(0, config.appearanceOptions);
mainWindow.hide();
}, 25);
};
}

const toggleMainWindow = () => {
function toggleMainWindow() {
if (mainWindow.isVisible()) {
hideMainWindow();
} else {
showMainWindow();
}
};
}

const getMaxWindowHeight = (maxSearchResultsPerPage: number, searchResultHeight: number, userInputHeight: number): number => {
function getMaxWindowHeight(maxSearchResultsPerPage: number, searchResultHeight: number, userInputHeight: number): number {
return Number(maxSearchResultsPerPage) * Number(searchResultHeight) + Number(userInputHeight);
};
}

const updateConfig = (updatedConfig: UserConfigOptions, needsIndexRefresh: boolean) => {
function updateConfig(updatedConfig: UserConfigOptions, needsIndexRefresh: boolean) {
if (updatedConfig.generalOptions.hotKey !== config.generalOptions.hotKey) {
registerGlobalKeyboardShortcut(toggleMainWindow, updatedConfig.generalOptions.hotKey);
}
Expand Down Expand Up @@ -120,9 +124,9 @@ const updateConfig = (updatedConfig: UserConfigOptions, needsIndexRefresh: boole
.catch((err) => logger.error(err));
})
.catch((err) => logger.error(err));
};
}

const updateMainWindowSize = (searchResultCount: number, appearanceOptions: AppearanceOptions, center?: boolean) => {
function updateMainWindowSize(searchResultCount: number, appearanceOptions: AppearanceOptions, center?: boolean) {
mainWindow.setResizable(true);
const windowHeight = searchResultCount > appearanceOptions.maxSearchResultsPerPage
? getMaxWindowHeight(appearanceOptions.maxSearchResultsPerPage, appearanceOptions.searchResultHeight, appearanceOptions.userInputHeight)
Expand All @@ -133,31 +137,31 @@ const updateMainWindowSize = (searchResultCount: number, appearanceOptions: Appe
mainWindow.center();
}
mainWindow.setResizable(false);
};
}

const reloadApp = () => {
function reloadApp() {
updateMainWindowSize(0, config.appearanceOptions);
searchEngine = currentOperatingSystem === OperatingSystem.macOS ? getMacOsProductionSearchEngine(config) : getWindowsProductionSearchEngine(config);
mainWindow.reload();
};
}

const quitApp = () => {
function quitApp() {
clearInterval(rescanInterval);
globalShortcut.unregisterAll();
app.quit();
};
}

const setAutoStartOptions = (userConfig: UserConfigOptions) => {
function setAutoStartOptions (userConfig: UserConfigOptions) {
if (!isDev()) {
app.setLoginItemSettings({
args: [],
openAtLogin: userConfig.generalOptions.autostart,
path: process.execPath,
});
}
};
}

const startApp = () => {
function startApp() {
mainWindow = new BrowserWindow({
center: true,
frame: false,
Expand All @@ -176,9 +180,10 @@ const startApp = () => {
updateMainWindowSize(0, config.appearanceOptions, recenter);
registerGlobalKeyboardShortcut(toggleMainWindow, config.generalOptions.hotKey);
setAutoStartOptions(config);
};
registerAllIpcListeners();
}

const openSettings = () => {
function openSettings() {
if (!settingsWindow || settingsWindow.isDestroyed()) {
settingsWindow = new BrowserWindow({
height: 700,
Expand All @@ -192,7 +197,56 @@ const openSettings = () => {
} else {
settingsWindow.focus();
}
};
}

function registerAllIpcListeners() {
ipcMain.on(IpcChannels.configUpdated, (event: Electron.Event, updatedConfig: UserConfigOptions, needsIndexRefresh: boolean) => {
updateConfig(updatedConfig, needsIndexRefresh);
});

ipcMain.on(IpcChannels.search, (event: Electron.Event, userInput: string) => {
searchEngine.getSearchResults(userInput)
.then((result) => {
updateMainWindowSize(result.length, config.appearanceOptions);
event.sender.send(IpcChannels.searchResponse, result);
})
.catch((err) => logger.error(err));
});

ipcMain.on(IpcChannels.execute, (event: Electron.Event, searchResultItem: SearchResultItem) => {
searchEngine.execute(searchResultItem)
.then(() => hideMainWindow())
.catch((err) => logger.error(err));
});

ipcMain.on(IpcChannels.reloadApp, () => {
reloadApp();
});

ipcMain.on(IpcChannels.openSettingsWindow, () => {
openSettings();
});

ipcMain.on(IpcChannels.ueliCommandExecuted, (command: UeliCommand) => {
switch (command.executionArgument) {
case UeliCommandExecutionArgument.Exit:
quitApp();
break;
case UeliCommandExecutionArgument.Reload:
reloadApp();
break;
case UeliCommandExecutionArgument.EditConfigFile:
configRepository.openConfigFile();
break;
case UeliCommandExecutionArgument.OpenSettings:
openSettings();
break;
default:
logger.error("Unhandled ueli command execution");
break;
}
});
}

app.on("ready", () => {
const gotSingleInstanceLock = app.requestSingleInstanceLock();
Expand All @@ -206,50 +260,3 @@ app.on("ready", () => {

app.on("window-all-closed", quitApp);
app.on("quit", app.quit);

ipcMain.on(IpcChannels.configUpdated, (event: Electron.Event, updatedConfig: UserConfigOptions, needsIndexRefresh: boolean) => {
updateConfig(updatedConfig, needsIndexRefresh);
});

ipcMain.on(IpcChannels.search, (event: Electron.Event, userInput: string) => {
searchEngine.getSearchResults(userInput)
.then((result) => {
updateMainWindowSize(result.length, config.appearanceOptions);
event.sender.send(IpcChannels.searchResponse, result);
})
.catch((err) => logger.error(err));
});

ipcMain.on(IpcChannels.execute, (event: Electron.Event, searchResultItem: SearchResultItem) => {
searchEngine.execute(searchResultItem)
.then(() => hideMainWindow())
.catch((err) => logger.error(err));
});

ipcMain.on(IpcChannels.reloadApp, () => {
reloadApp();
});

ipcMain.on(IpcChannels.openSettingsWindow, () => {
openSettings();
});

ipcMain.on(IpcChannels.ueliCommandExecuted, (command: UeliCommand) => {
switch (command.executionArgument) {
case UeliCommandExecutionArgument.Exit:
quitApp();
break;
case UeliCommandExecutionArgument.Reload:
reloadApp();
break;
case UeliCommandExecutionArgument.EditConfigFile:
configRepository.openConfigFile();
break;
case UeliCommandExecutionArgument.OpenSettings:
openSettings();
break;
default:
logger.error("Unhandled ueli command execution");
break;
}
});
1 change: 1 addition & 0 deletions src/main/plugin-type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum PluginType {
ApplicationSearchPlugin = "application-search-plugin",
UeliCommandSearchPlugin = "ueli-command-search-plugin",
ShortcutsSearchPlugin = "shortcuts-search-plugin",
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Application } from "./application";
import { dirname, basename } from "path";
import { UserConfigOptions } from "../../../common/config/user-config-options";
import { ApplicationSearchOptions } from "./application-search-options";
import { IconType } from "../../../common/icon-type";
import { IconType } from "../../../common/icon/icon-type";

export class ApplicationSearchPlugin implements SearchPlugin {
public readonly pluginType = PluginType.ApplicationSearchPlugin;
Expand Down Expand Up @@ -66,8 +66,8 @@ export class ApplicationSearchPlugin implements SearchPlugin {
}

public updateConfig(config: UserConfigOptions): Promise<void> {
this.config = config.applicationSearchOptions;
return new Promise((resolve, reject) => {
this.config = config.applicationSearchOptions;
this.applicationRepository.updateConfig(config.applicationSearchOptions)
.then(() => resolve())
.catch((err) => reject(err));
Expand Down
20 changes: 20 additions & 0 deletions src/main/plugins/shorcuts-plugin/shortcut-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Shortcut } from "./shortcut";
import { ShortcutType } from "./shortcut-type";
import { IconTypeHelpers } from "../../../common/icon/icon-type-helpers";

export class ShortcutHelpers {
public static isValidShortcut(shortcut: Shortcut): boolean {
return shortcut.description !== undefined
&& shortcut.description.length !== 0
&& shortcut.executionArgument !== undefined
&& shortcut.executionArgument.length !== 0
&& shortcut.icon !== undefined
&& shortcut.icon.parameter !== undefined
&& IconTypeHelpers.isValidIconType(shortcut.icon.type)
&& this.isValidShortcuType(shortcut.type);
}

public static isValidShortcuType(shortcutType: ShortcutType): boolean {
return Object.values(ShortcutType).find((s) => s === shortcutType) !== undefined;
}
}
4 changes: 4 additions & 0 deletions src/main/plugins/shorcuts-plugin/shortcut-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum ShortcutType {
Url = "URL",
FilePath = "File path",
}
Loading

0 comments on commit 2d04320

Please sign in to comment.