Initial settings tab

This commit is contained in:
Geomitron
2020-02-13 22:33:14 -05:00
parent c6b549340b
commit 49cba89a11
14 changed files with 204 additions and 47 deletions

View File

@@ -1,12 +1,13 @@
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { BrowseComponent } from './components/browse/browse.component'
import { SettingsComponent } from './components/settings/settings.component'
const routes: Routes = [
{ path: 'browse', component: BrowseComponent },
{ path: 'library', component: BrowseComponent },
{ path: 'settings', component: BrowseComponent },
{ path: 'settings', component: SettingsComponent },
{ path: 'about', component: BrowseComponent }, // TODO: replace these with the correct components
{ path: '**', redirectTo: '/browse'}
]

View File

@@ -12,7 +12,8 @@ import { ChartSidebarComponent } from './components/browse/chart-sidebar/chart-s
import { ResultTableRowComponent } from './components/browse/result-table/result-table-row/result-table-row.component';
import { DownloadsModalComponent } from './components/browse/status-bar/downloads-modal/downloads-modal.component';
import { ProgressBarDirective } from './core/directives/progress-bar.directive';
import { CheckboxDirective } from './core/directives/checkbox.directive'
import { CheckboxDirective } from './core/directives/checkbox.directive';
import { SettingsComponent } from './components/settings/settings.component'
@NgModule({
declarations: [
@@ -26,7 +27,8 @@ import { CheckboxDirective } from './core/directives/checkbox.directive'
ResultTableRowComponent,
DownloadsModalComponent,
ProgressBarDirective,
CheckboxDirective
CheckboxDirective,
SettingsComponent
],
imports: [
BrowserModule,

View File

@@ -19,7 +19,7 @@
<a class="item">Charter</a>
</div>
</div>
<div class="item right">
<!-- <div class="item right">
<button class="ui positive disabled button">Bulk Download</button>
</div>
</div> -->
</div>

View File

@@ -53,6 +53,6 @@ export class DownloadsModalComponent {
}
openFolder(filepath: string) {
this.electronService.sendIPC('open-folder', filepath)
this.electronService.showFolder(filepath)
}
}

View File

@@ -0,0 +1,29 @@
<h3 class="ui header">Paths</h3>
<div class="ui form">
<div class="field">
<label>Chart library directory</label>
<div class="ui action input">
<input [value]="settingsService.libraryDirectory" class="default-cursor" readonly type="text"
placeholder="No directory selected!">
<button *ngIf="settingsService.libraryDirectory != undefined" (click)="openLibraryDirectory()"
class="ui button">Open Folder</button>
<button (click)="getLibraryDirectory()" class="ui button teal">Choose</button>
</div>
</div>
</div>
<h3 class="ui header">Cache</h3>
<div>Current Cache Size: <div class="ui label" style="margin-left: 1em;">{{cacheSize}}</div>
</div>
<button style="margin-top: 0.5em;" (click)="clearCache()" class="ui button">Clear Cache</button>
<h3 class="ui header">Theme</h3>
<div #themeDropdown class="ui selection dropdown mr">
<input type="hidden" name="sort" [value]="settingsService.theme">
<i class="dropdown icon"></i>
<div class="default text">Default</div>
<div class="menu">
<div class="item" [attr.data-value]="i" *ngFor="let theme of settingsService.builtinThemes; let i = index">{{theme}}
</div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
:host {
flex: 1;
padding: 2em;
overflow-y: scroll;
}
.default-cursor {
cursor: default;
pointer-events: none;
}

View File

@@ -0,0 +1,52 @@
import { Component, OnInit, ViewChild, ElementRef, AfterViewInit } from '@angular/core'
import { ElectronService } from 'src/app/core/services/electron.service'
import { SettingsService } from 'src/app/core/services/settings.service'
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit, AfterViewInit {
@ViewChild('themeDropdown', { static: true }) themeDropdown: ElementRef
cacheSize = 'Calculating...'
constructor(private settingsService: SettingsService, private electronService: ElectronService) { }
async ngOnInit() {
const cacheSize = await this.settingsService.getCacheSize()
this.cacheSize = Math.round(cacheSize / 1000000) + ' MB'
}
ngAfterViewInit() {
$(this.themeDropdown.nativeElement).dropdown({
onChange: (_value: string, text: string) => {
this.settingsService.theme = text
}
})
}
async clearCache() {
this.cacheSize = 'Please wait...'
await this.settingsService.clearCache()
this.cacheSize = 'Cleared!'
}
async getLibraryDirectory() {
const result = await this.electronService.showOpenDialog({
title: 'Choose library folder',
buttonLabel: 'This is where my charts are!',
defaultPath: this.settingsService.libraryDirectory || '',
properties: ['openDirectory']
})
if (result.canceled == false) {
this.settingsService.libraryDirectory = result.filePaths[0]
}
}
async openLibraryDirectory() {
this.electronService.openFolder(this.settingsService.libraryDirectory)
}
}

View File

@@ -11,14 +11,14 @@ export class ToolbarComponent {
constructor(private electronService: ElectronService) { }
minimize() {
this.electronService.remote.getCurrentWindow().minimize()
this.electronService.currentWindow.minimize()
}
maximize() {
this.electronService.remote.getCurrentWindow().maximize()
this.electronService.currentWindow.maximize()
}
close() {
this.electronService.remote.app.quit()
this.electronService.quit()
}
}

View File

@@ -2,40 +2,29 @@ import { Injectable } from '@angular/core'
// If you import a module but never use any of the imported values other than as TypeScript types,
// the resulting javascript file will look as if you never imported the module at all.
import { ipcRenderer, webFrame, remote } from 'electron'
import * as childProcess from 'child_process'
import * as fs from 'fs'
import * as util from 'util'
import * as electron from 'electron'
import { IPCInvokeEvents, IPCEmitEvents } from '../../../electron/shared/IPCHandler'
@Injectable({
providedIn: 'root'
})
export class ElectronService {
ipcRenderer: typeof ipcRenderer
webFrame: typeof webFrame
remote: typeof remote
childProcess: typeof childProcess
fs: typeof fs
util: typeof util
electron: typeof electron
get isElectron() {
return !!(window && window.process && window.process.type)
}
constructor() {
// Conditional imports
if (this.isElectron) {
this.ipcRenderer = window.require('electron').ipcRenderer
this.webFrame = window.require('electron').webFrame
this.remote = window.require('electron').remote
this.childProcess = window.require('child_process')
this.fs = window.require('fs')
this.util = window.require('util')
this.electron = window.require('electron')
}
}
get currentWindow() {
return this.electron.remote.getCurrentWindow()
}
/**
* Calls an async function in the main process.
* @param event The name of the IPC event to invoke.
@@ -43,7 +32,7 @@ export class ElectronService {
* @returns A promise that resolves to the output data.
*/
async invoke<E extends keyof IPCInvokeEvents>(event: E, data: IPCInvokeEvents[E]['input']) {
return this.ipcRenderer.invoke(event, data) as Promise<IPCInvokeEvents[E]['output']>
return this.electron.ipcRenderer.invoke(event, data) as Promise<IPCInvokeEvents[E]['output']>
}
/**
@@ -52,7 +41,7 @@ export class ElectronService {
* @param data The data object to send across IPC.
*/
sendIPC<E extends keyof IPCEmitEvents>(event: E, data: IPCEmitEvents[E]) {
this.ipcRenderer.send(event, data)
this.electron.ipcRenderer.send(event, data)
}
/**
@@ -61,8 +50,28 @@ export class ElectronService {
* @param callback The data object to receive across IPC.
*/
receiveIPC<E extends keyof IPCEmitEvents>(event: E, callback: (result: IPCEmitEvents[E]) => void) {
this.ipcRenderer.on(event, (_event, ...results) => {
this.electron.ipcRenderer.on(event, (_event, ...results) => {
callback(results[0])
})
}
quit() {
this.electron.remote.app.quit()
}
openFolder(filepath: string) {
this.electron.shell.openItem(filepath)
}
showFolder(filepath: string) {
this.electron.shell.showItemInFolder(filepath)
}
showOpenDialog(options: Electron.OpenDialogOptions) {
return this.electron.remote.dialog.showOpenDialog(this.currentWindow, options)
}
get defaultSession() {
return this.electron.remote.session.defaultSession
}
}

View File

@@ -6,8 +6,10 @@ import { Settings } from 'src/electron/shared/Settings'
providedIn: 'root'
})
export class SettingsService {
readonly builtinThemes = ['Default', 'Dark']
private settings: Settings
private currentThemeLink: HTMLLinkElement
constructor(private electronService: ElectronService) { }
@@ -17,4 +19,47 @@ export class SettingsService {
}
return this.settings
}
saveSettings() {
if (this.settings != undefined) {
this.electronService.sendIPC('update-settings', this.settings)
}
}
changeTheme(theme: string) {
if (this.currentThemeLink != undefined) this.currentThemeLink.remove()
if (theme == 'Default') { return }
const link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = `assets/themes/${theme}.css`
this.currentThemeLink = document.head.appendChild(link)
}
async getCacheSize() {
return this.electronService.defaultSession.getCacheSize()
}
async clearCache() {
this.saveSettings()
return this.electronService.defaultSession.clearCache()
}
get libraryDirectory() {
return this.settings == undefined ? '' : this.settings.libraryPath
}
set libraryDirectory(newValue: string) {
this.settings.libraryPath = newValue
this.saveSettings()
}
get theme() {
return this.settings == undefined ? '' : this.settings.theme
}
set theme(newValue: string) {
this.settings.theme = newValue
this.changeTheme(newValue)
this.saveSettings()
}
}