Skip to content

Commit

Permalink
Added open file dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverschwendener committed Feb 8, 2019
1 parent f24fd0b commit 6471ef0
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 64 deletions.
30 changes: 15 additions & 15 deletions main.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./styles/app.css">
<title>ueli</title>
</head>
<body>
<div id="app" @keydown="onKeyPress">
<user-styles :appearance="config.appearanceOptions"></user-styles>
<user-input :appearance="config.appearanceOptions"></user-input>
<search-results :appearance="config.appearanceOptions"></search-results>
</div>
<script src="./bundle/renderer.js"></script>
</body>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./styles/app.css">
<title>ueli</title>
</head>
<body>
<div id="app" @keyup="onKeyPress">
<user-styles :appearance="config.appearanceOptions"></user-styles>
<user-input :appearance="config.appearanceOptions"></user-input>
<search-results :appearance="config.appearanceOptions"></search-results>
</div>
<script src="./bundle/renderer.js"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions src/common/ipc-channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export enum IpcChannels {
ueliCommandExecuted = "ueli-command-executed",
folderPathRequested = "folder-path-requested",
folderPathResult = "folder-path-result",
folderAndFilePathsRequested = "folder-and-file-paths-requested",
folderAndFilePathsResult = "folder-and-file-paths-result",
}
1 change: 0 additions & 1 deletion src/main/helpers/file-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export class FileHelpers {
fileLists.forEach((fileList) => {
files = files.concat(fileList);
});

resolve(files);
})
.catch((fileHandleError) => reject(fileHandleError));
Expand Down
8 changes: 8 additions & 0 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ function registerAllIpcListeners() {
});
});

ipcMain.on(IpcChannels.folderAndFilePathsRequested, (event: Electron.Event) => {
dialog.showOpenDialog(settingsWindow, {
properties: ["openFile", "openDirectory"],
}, (filePaths: string[]) => {
event.sender.send(IpcChannels.folderAndFilePathsResult, filePaths);
});
});

ipcMain.on(IpcChannels.ueliCommandExecuted, (command: UeliCommand) => {
switch (command.executionArgument) {
case UeliCommandExecutionArgument.Exit:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ApplicationSearchOptions } from "./application-search-options";
import { FileHelpers } from "../../helpers/file-helpers";
import { ApplicationIconService } from "./application-icon-service";
import { getApplicationIconFilePath } from "./application-icon-helpers";
import { uniq } from "lodash";

export class FileApplicationRepository implements ApplicationRepository {
private readonly applicationIconService: ApplicationIconService;
Expand All @@ -30,22 +31,22 @@ export class FileApplicationRepository implements ApplicationRepository {
resolve();
} else {
FileHelpers.readFilesFromFoldersRecursively(this.config.applicationFolders)
.then((files) => {
if (files.length === 0) {
this.applications = [];
resolve();
}
.then((files) => {
if (files.length === 0) {
this.applications = [];
resolve();
}

const applications = files
.filter((file) => this.filterByApplicationFileExtensions(file))
.map((applicationFile): Application => this.createApplicationFromFilePath(applicationFile));
const applications = uniq(files)
.filter((file) => this.filterByApplicationFileExtensions(file))
.map((applicationFile): Application => this.createApplicationFromFilePath(applicationFile));

this.applicationIconService.generateAppIcons(applications);
applications.forEach((application) => application.icon = getApplicationIconFilePath(application));
this.applications = applications;
resolve();
})
.catch((err) => reject(err));
this.applicationIconService.generateAppIcons(applications);
applications.forEach((application) => application.icon = getApplicationIconFilePath(application));
this.applications = applications;
resolve();
})
.catch((err) => reject(err));
}
});
}
Expand Down
40 changes: 23 additions & 17 deletions src/renderer/application-search-options-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { defaultApplicationSearchOptions } from "../main/plugins/application-sea
import { cloneDeep } from "lodash";
import { Settings } from "./settings";
import { SettingsNotificationType } from "./settings-notification-type";
import { showNotification } from "./notifications";

export const applicationSearchSettingsComponent = Vue.extend({
data() {
Expand All @@ -15,20 +16,27 @@ export const applicationSearchSettingsComponent = Vue.extend({
};
},
methods: {
addApplicationFileExtension() {
addApplicationFileExtension(applicationFileExtension: string) {
const config: UserConfigOptions = this.config;
config.applicationSearchOptions.applicationFileExtensions.push(this.newApplicationFileExtension);
this.newApplicationFileExtension = "";
this.updateConfig(true);
if (config.applicationSearchOptions.applicationFileExtensions.find((a) => a === applicationFileExtension) !== undefined) {
showNotification(`"${applicationFileExtension}" already exists in your list`, SettingsNotificationType.Info);
} else {
config.applicationSearchOptions.applicationFileExtensions.push(applicationFileExtension);
this.updateConfig(true);
}
},
addApplicationFolder() {
addApplicationFolder(folderPath: string) {
const config: UserConfigOptions = this.config;
config.applicationSearchOptions.applicationFolders.push(this.newApplicationFolder);
this.newApplicationFolder = "";
this.updateConfig(true);
const folderAlreadyExistsInList = config.applicationSearchOptions.applicationFolders.find((a) => a === folderPath) !== undefined;
if (folderAlreadyExistsInList) {
showNotification(`Folder "${folderPath}" already exists in your list`, SettingsNotificationType.Info);
} else {
config.applicationSearchOptions.applicationFolders.push(folderPath);
this.updateConfig(true);
}
},
onAddFileExtensionClick() {
//
vueEventDispatcher.$emit(VueEventChannels.openNewApplicationFileExtensionModal);
},
onAddFolderClick() {
vueEventDispatcher.$emit(VueEventChannels.openNewApplicationFolderModal);
Expand Down Expand Up @@ -79,14 +87,11 @@ export const applicationSearchSettingsComponent = Vue.extend({
});

vueEventDispatcher.$on(VueEventChannels.applicationFolderAdded, (folderPath: string) => {
const config: UserConfigOptions = this.config;
const folderAlreadyExistsInList = config.applicationSearchOptions.applicationFolders.find((a) => a === folderPath) !== undefined;
if (folderAlreadyExistsInList) {
vueEventDispatcher.$emit(VueEventChannels.pushNotification, `Folder "${folderPath}" already exists in your list`, SettingsNotificationType.Info);
} else {
config.applicationSearchOptions.applicationFolders.push(folderPath);
this.updateConfig(true);
}
this.addApplicationFolder(folderPath);
});

vueEventDispatcher.$on(VueEventChannels.applicationFileExtensionAdded, (applicationFileExtension: string) => {
this.addApplicationFileExtension(applicationFileExtension);
});
},
props: ["config"],
Expand Down Expand Up @@ -173,6 +178,7 @@ export const applicationSearchSettingsComponent = Vue.extend({
<h6 v-else class="title is-6 has-text-danger">Application search is disabled</h6>
</div>
<new-application-folder-modal></new-application-folder-modal>
<new-application-file-extension-modal></new-application-file-extension-modal>
</div>
`,
});
9 changes: 9 additions & 0 deletions src/renderer/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ export function getFolderPaths(): Promise<string[]> {
});
});
}

export function getFileAndFolderPaths(): Promise<string[]> {
return new Promise((resolve, reject) => {
ipcRenderer.send(IpcChannels.folderAndFilePathsRequested);
ipcRenderer.once(IpcChannels.folderAndFilePathsResult, (event: Electron.Event, foldersAndFiles: string[]) => {
resolve(foldersAndFiles);
});
});
}
79 changes: 79 additions & 0 deletions src/renderer/new-application-fileextension-modal-component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Vue from "vue";
import { vueEventDispatcher } from "./vue-event-dispatcher";
import { VueEventChannels } from "./vue-event-channels";
import { showNotification } from "./notifications";
import { SettingsNotificationType } from "./settings-notification-type";

export const newApplicationFileExtensionModalComponent = Vue.extend({
data() {
return {
newApplicationFileExtension: "",
visible: false,
};
},
methods: {
saveButtonClick() {
const applicationFileExtension: string = this.newApplicationFileExtension;
const isValidApplicationFileExtension = applicationFileExtension !== undefined
&& applicationFileExtension.startsWith(".")
&& applicationFileExtension.replace(".", "").length > 0;

if (isValidApplicationFileExtension) {
vueEventDispatcher.$emit(VueEventChannels.applicationFileExtensionAdded, applicationFileExtension);
this.closeModal();
} else {
showNotification(`"${applicationFileExtension}" is not a valid file extension`, SettingsNotificationType.Error);
}
},
closeModal() {
this.newApplicationFileExtension = "";
this.visible = false;
},
},
mounted() {
vueEventDispatcher.$on(VueEventChannels.openNewApplicationFileExtensionModal, () => {
this.visible = true;
});
},
template: `
<div class="modal" :class="{ 'is-active' : visible }">
<div class="modal-background" @click="closeModal"></div>
<div class="modal-content">
<div class="message">
<div class="message-header">
<p>Add new application folder</p>
<button @click="closeModal" class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
<div class="field">
<label class="label">
Application file extension
</label>
<div class="control is-expanded">
<input class="input" type="text" v-model="newApplicationFileExtension" autofocus>
</div>
</div>
<div class="field is-grouped is-grouped-right">
<div class="control">
<button class="button is-danger" @click="closeModal">
<span class="icon">
<i class="fas fa-times"></i>
</span>
<span>Cancel</span>
</button>
</div>
<div class="control">
<button :disabled="newApplicationFileExtension.length === 0" class="button is-success" @click="saveButtonClick">
<span class="icon">
<i class="fas fa-check"></i>
</span>
<span>Save</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`,
});
18 changes: 10 additions & 8 deletions src/renderer/new-application-folder-modal-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { VueEventChannels } from "./vue-event-channels";
import { FileHelpers } from "../main/helpers/file-helpers";
import { SettingsNotificationType } from "./settings-notification-type";
import { getFolderPaths } from "./dialogs";
import { showNotification } from "./notifications";

export const newApplicationFolderModalComponent = Vue.extend({
data() {
Expand Down Expand Up @@ -32,11 +33,13 @@ export const newApplicationFolderModalComponent = Vue.extend({
vueEventDispatcher.$emit(VueEventChannels.applicationFolderAdded, this.newApplicationFolder);
this.closeModal();
})
.catch((err: string) => {
vueEventDispatcher.$emit(VueEventChannels.pushNotification, err, SettingsNotificationType.Error);
});
.catch((err: string) => showNotification(err, SettingsNotificationType.Error));
},
validateFolderPath(folderPath: string): Promise<void> {
const notAFolderError = `"${folderPath}" is not a folder`;
const folderDoesNotExistError = `${folderPath} does not exist`;
const genericError = `Error while trying to validate folder path: ${folderPath}`;

return new Promise((resolve, reject) => {
FileHelpers.fileExists(folderPath)
.then((fileExists) => {
Expand All @@ -46,15 +49,15 @@ export const newApplicationFolderModalComponent = Vue.extend({
if (stats.stats.isDirectory()) {
resolve();
} else {
reject("Specified path is not a folder");
reject(notAFolderError);
}
})
.catch((err) => reject(err));
} else {
reject("Folder does not exist");
reject(folderDoesNotExistError);
}
})
.catch(() => reject(`Error while trying to validate folder path: ${folderPath}`));
.catch(() => reject(genericError));
});
},
},
Expand Down Expand Up @@ -98,7 +101,7 @@ export const newApplicationFolderModalComponent = Vue.extend({
</button>
</div>
<div class="control">
<button class="button is-success" @click="saveButtonClick">
<button :disabled="newApplicationFolder.length === 0" class="button is-success" @click="saveButtonClick">
<span class="icon">
<i class="fas fa-check"></i>
</span>
Expand All @@ -109,7 +112,6 @@ export const newApplicationFolderModalComponent = Vue.extend({
</div>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="closeModal"></button>
</div>
`,
});
7 changes: 7 additions & 0 deletions src/renderer/notifications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SettingsNotificationType } from "./settings-notification-type";
import { vueEventDispatcher } from "./vue-event-dispatcher";
import { VueEventChannels } from "./vue-event-channels";

export function showNotification(message: string, notificationType: SettingsNotificationType) {
vueEventDispatcher.$emit(VueEventChannels.notification, message, notificationType);
}
2 changes: 2 additions & 0 deletions src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { shortcutSettingsComponent } from "./shortcut-settings-component";
import { shortcutEditingModal } from "./shortcut-editing-modal-component";
import { cloneDeep } from "lodash";
import { newApplicationFolderModalComponent } from "./new-application-folder-modal-component";
import { newApplicationFileExtensionModalComponent } from "./new-application-fileextension-modal-component";

Vue.component("user-input", userInputComponent);
Vue.component("search-results", searchResultsComponent);
Expand All @@ -36,6 +37,7 @@ Vue.component("user-styles", userStylesComponent);
Vue.component("shortcut-settings", shortcutSettingsComponent);
Vue.component("shortcut-editing-modal", shortcutEditingModal);
Vue.component("new-application-folder-modal", newApplicationFolderModalComponent);
Vue.component("new-application-file-extension-modal", newApplicationFileExtensionModalComponent);

// tslint:disable-next-line:no-unused-expression
new Vue({
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/settings-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const settingsComponent = Vue.extend({
mounted() {
vueEventDispatcher.$emit(VueEventChannels.showSetting, Settings.General);

vueEventDispatcher.$on(VueEventChannels.pushNotification, (message: string, type: SettingsNotificationType) => {
vueEventDispatcher.$on(VueEventChannels.notification, (message: string, type: SettingsNotificationType) => {
this.showNotification(message, type);
});

Expand Down
Loading

0 comments on commit 6471ef0

Please sign in to comment.