mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 14:19:38 +00:00
Restructure; use DaisyUI
This commit is contained in:
@@ -1,34 +1,35 @@
|
||||
import { AfterViewInit, Directive, ElementRef, EventEmitter, Output } from '@angular/core'
|
||||
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'
|
||||
|
||||
@Directive({
|
||||
selector: '[appCheckbox]',
|
||||
})
|
||||
export class CheckboxDirective implements AfterViewInit {
|
||||
export class CheckboxDirective {
|
||||
@Output() checked = new EventEmitter<boolean>()
|
||||
|
||||
_isChecked = false
|
||||
|
||||
constructor(private checkbox: ElementRef) { }
|
||||
|
||||
ngAfterViewInit() {
|
||||
$(this.checkbox.nativeElement).checkbox({
|
||||
onChecked: () => {
|
||||
this.checked.emit(true)
|
||||
this._isChecked = true
|
||||
},
|
||||
onUnchecked: () => {
|
||||
this.checked.emit(false)
|
||||
this._isChecked = false
|
||||
},
|
||||
})
|
||||
}
|
||||
// ngAfterViewInit() {
|
||||
// TODO
|
||||
// $(this.checkbox.nativeElement).checkbox({
|
||||
// onChecked: () => {
|
||||
// this.checked.emit(true)
|
||||
// this._isChecked = true
|
||||
// },
|
||||
// onUnchecked: () => {
|
||||
// this.checked.emit(false)
|
||||
// this._isChecked = false
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
|
||||
check(isChecked: boolean) {
|
||||
this._isChecked = isChecked
|
||||
if (isChecked) {
|
||||
$(this.checkbox.nativeElement).checkbox('check')
|
||||
this.checkbox.nativeElement.checked = true
|
||||
} else {
|
||||
$(this.checkbox.nativeElement).checkbox('uncheck')
|
||||
this.checkbox.nativeElement.checked = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Directive, ElementRef, Input } from '@angular/core'
|
||||
|
||||
import * as _ from 'lodash'
|
||||
|
||||
@Directive({
|
||||
selector: '[appProgressBar]',
|
||||
})
|
||||
@@ -17,13 +15,14 @@ export class ProgressBarDirective {
|
||||
}
|
||||
|
||||
constructor(private element: ElementRef) {
|
||||
this.progress = _.throttle((percent: number) => this.$progressBar.progress('set').percent(percent), 100)
|
||||
// TODO
|
||||
// this.progress = throttle((percent: number) => this.$progressBar.progress('set').percent(percent), 100)
|
||||
}
|
||||
|
||||
private get $progressBar() {
|
||||
if (!this._$progressBar) {
|
||||
this._$progressBar = $(this.element.nativeElement)
|
||||
}
|
||||
return this._$progressBar
|
||||
}
|
||||
// private get $progressBar() {
|
||||
// if (!this._$progressBar) {
|
||||
// this._$progressBar = $(this.element.nativeElement)
|
||||
// }
|
||||
// return this._$progressBar
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
import { ElectronService } from './electron.service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AlbumArtService {
|
||||
|
||||
private imageCache: { [songID: number]: string } = {}
|
||||
|
||||
constructor(private electronService: ElectronService) { }
|
||||
|
||||
async getImage(songID: number): Promise<string | null> {
|
||||
if (this.imageCache[songID] == undefined) {
|
||||
const albumArtResult = await this.electronService.invoke('album-art', songID)
|
||||
if (albumArtResult) {
|
||||
this.imageCache[songID] = albumArtResult.base64Art
|
||||
} else {
|
||||
this.imageCache[songID] = null
|
||||
}
|
||||
}
|
||||
|
||||
return this.imageCache[songID]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core'
|
||||
|
||||
import { DownloadProgress, NewDownload } from '../../../electron/shared/interfaces/download.interface'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { DownloadProgress, NewDownload } from '../../../../src-shared/interfaces/download.interface'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -11,13 +10,13 @@ export class DownloadService {
|
||||
private downloadUpdatedEmitter = new EventEmitter<DownloadProgress>()
|
||||
private downloads: DownloadProgress[] = []
|
||||
|
||||
constructor(private electronService: ElectronService) {
|
||||
this.electronService.receiveIPC('download-updated', result => {
|
||||
constructor() {
|
||||
window.electron.on.downloadUpdated(result => {
|
||||
// Update <this.downloads> with result
|
||||
const thisDownloadIndex = this.downloads.findIndex(download => download.versionID == result.versionID)
|
||||
if (result.type == 'cancel') {
|
||||
this.downloads = this.downloads.filter(download => download.versionID != result.versionID)
|
||||
} else if (thisDownloadIndex == -1) {
|
||||
const thisDownloadIndex = this.downloads.findIndex(download => download.versionID === result.versionID)
|
||||
if (result.type === 'cancel') {
|
||||
this.downloads = this.downloads.filter(download => download.versionID !== result.versionID)
|
||||
} else if (thisDownloadIndex === -1) {
|
||||
this.downloads.push(result)
|
||||
} else {
|
||||
this.downloads[thisDownloadIndex] = result
|
||||
@@ -32,7 +31,7 @@ export class DownloadService {
|
||||
}
|
||||
|
||||
get completedCount() {
|
||||
return this.downloads.filter(download => download.type == 'done').length
|
||||
return this.downloads.filter(download => download.type === 'done').length
|
||||
}
|
||||
|
||||
get totalDownloadingPercent() {
|
||||
@@ -48,15 +47,15 @@ export class DownloadService {
|
||||
}
|
||||
|
||||
get anyErrorsExist() {
|
||||
return this.downloads.find(download => download.type == 'error') ? true : false
|
||||
return this.downloads.find(download => download.type === 'error') ? true : false
|
||||
}
|
||||
|
||||
addDownload(versionID: number, newDownload: NewDownload) {
|
||||
if (!this.downloads.find(download => download.versionID == versionID)) { // Don't download something twice
|
||||
if (this.downloads.every(download => download.type == 'done')) { // Reset overall progress bar if it finished
|
||||
if (!this.downloads.find(download => download.versionID === versionID)) { // Don't download something twice
|
||||
if (this.downloads.every(download => download.type === 'done')) { // Reset overall progress bar if it finished
|
||||
this.downloads.forEach(download => download.stale = true)
|
||||
}
|
||||
this.electronService.sendIPC('download', { action: 'add', versionID, data: newDownload })
|
||||
window.electron.emit.download({ action: 'add', versionID, data: newDownload })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,25 +64,25 @@ export class DownloadService {
|
||||
}
|
||||
|
||||
cancelDownload(versionID: number) {
|
||||
const removedDownload = this.downloads.find(download => download.versionID == versionID)
|
||||
const removedDownload = this.downloads.find(download => download.versionID === versionID)!
|
||||
if (['error', 'done'].includes(removedDownload.type)) {
|
||||
this.downloads = this.downloads.filter(download => download.versionID != versionID)
|
||||
this.downloads = this.downloads.filter(download => download.versionID !== versionID)
|
||||
removedDownload.type = 'cancel'
|
||||
this.downloadUpdatedEmitter.emit(removedDownload)
|
||||
} else {
|
||||
this.electronService.sendIPC('download', { action: 'cancel', versionID })
|
||||
window.electron.emit.download({ action: 'cancel', versionID })
|
||||
}
|
||||
}
|
||||
|
||||
cancelCompleted() {
|
||||
for (const download of this.downloads) {
|
||||
if (download.type == 'done') {
|
||||
if (download.type === 'done') {
|
||||
this.cancelDownload(download.versionID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retryDownload(versionID: number) {
|
||||
this.electronService.sendIPC('download', { action: 'retry', versionID })
|
||||
window.electron.emit.download({ action: 'retry', versionID })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
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 * as electron from 'electron'
|
||||
|
||||
import { IPCEmitEvents, IPCInvokeEvents } from '../../../electron/shared/IPCHandler'
|
||||
|
||||
const { app, getCurrentWindow, dialog, session } = window.require('@electron/remote')
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ElectronService {
|
||||
electron: typeof electron
|
||||
|
||||
get isElectron() {
|
||||
return !!(window && window.process && window.process.type)
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (this.isElectron) {
|
||||
this.electron = window.require('electron')
|
||||
this.receiveIPC('log', results => results.forEach(result => console.log(result)))
|
||||
}
|
||||
}
|
||||
|
||||
get currentWindow() {
|
||||
return getCurrentWindow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an async function in the main process.
|
||||
* @param event The name of the IPC event to invoke.
|
||||
* @param data The data object to send across IPC.
|
||||
* @returns A promise that resolves to the output data.
|
||||
*/
|
||||
async invoke<E extends keyof IPCInvokeEvents>(event: E, data: IPCInvokeEvents[E]['input']) {
|
||||
return this.electron.ipcRenderer.invoke(event, data) as Promise<IPCInvokeEvents[E]['output']>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an IPC message to the main process.
|
||||
* @param event The name of the IPC event to send.
|
||||
* @param data The data object to send across IPC.
|
||||
*/
|
||||
sendIPC<E extends keyof IPCEmitEvents>(event: E, data: IPCEmitEvents[E]) {
|
||||
this.electron.ipcRenderer.send(event, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives an IPC message from the main process.
|
||||
* @param event The name of the IPC event to receive.
|
||||
* @param callback The data object to receive across IPC.
|
||||
*/
|
||||
receiveIPC<E extends keyof IPCEmitEvents>(event: E, callback: (result: IPCEmitEvents[E]) => void) {
|
||||
this.electron.ipcRenderer.on(event, (_event, ...results) => {
|
||||
callback(results[0])
|
||||
})
|
||||
}
|
||||
|
||||
quit() {
|
||||
app.exit()
|
||||
}
|
||||
|
||||
openFolder(filepath: string) {
|
||||
this.electron.shell.openPath(filepath)
|
||||
}
|
||||
|
||||
showFolder(filepath: string) {
|
||||
this.electron.shell.showItemInFolder(filepath)
|
||||
}
|
||||
|
||||
showOpenDialog(options: Electron.OpenDialogOptions) {
|
||||
return dialog.showOpenDialog(this.currentWindow, options)
|
||||
}
|
||||
|
||||
get defaultSession() {
|
||||
return session.defaultSession
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core'
|
||||
|
||||
import { SongResult, SongSearch } from 'src/electron/shared/interfaces/search.interface'
|
||||
import { VersionResult } from 'src/electron/shared/interfaces/songDetails.interface'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { SongResult, SongSearch } from '../../../../src-shared/interfaces/search.interface'
|
||||
import { VersionResult } from '../../../../src-shared/interfaces/songDetails.interface'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -17,14 +16,12 @@ export class SearchService {
|
||||
private currentQuery: SongSearch
|
||||
private _allResultsVisible = true
|
||||
|
||||
constructor(private electronService: ElectronService) { }
|
||||
|
||||
async newSearch(query: SongSearch) {
|
||||
if (this.awaitingResults) { return }
|
||||
this.awaitingResults = true
|
||||
this.currentQuery = query
|
||||
try {
|
||||
this.results = this.trimLastChart(await this.electronService.invoke('song-search', this.currentQuery))
|
||||
this.results = this.trimLastChart(await window.electron.invoke.songSearch(this.currentQuery))
|
||||
this.errorStateEmitter.emit(false)
|
||||
} catch (err) {
|
||||
this.results = []
|
||||
@@ -74,7 +71,7 @@ export class SearchService {
|
||||
if (!this.awaitingResults && !this._allResultsVisible) {
|
||||
this.awaitingResults = true
|
||||
this.currentQuery.offset += 50
|
||||
this.results.push(...this.trimLastChart(await this.electronService.invoke('song-search', this.currentQuery)))
|
||||
this.results.push(...this.trimLastChart(await window.electron.invoke.songSearch(this.currentQuery)))
|
||||
this.awaitingResults = false
|
||||
|
||||
this.resultsChangedEmitter.emit(this.results)
|
||||
@@ -105,7 +102,7 @@ export class SearchService {
|
||||
versionResults.forEach(version => dates[version.versionID] = new Date(version.lastModified).getTime())
|
||||
versionResults.sort((v1, v2) => {
|
||||
const diff = dates[v2.versionID] - dates[v1.versionID]
|
||||
if (Math.abs(diff) < 6.048e+8 && v1.driveData.inChartPack != v2.driveData.inChartPack) {
|
||||
if (Math.abs(diff) < 6.048e+8 && v1.driveData.inChartPack !== v2.driveData.inChartPack) {
|
||||
if (v1.driveData.inChartPack) {
|
||||
return 1 // prioritize v2
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core'
|
||||
|
||||
import { SongResult } from '../../../electron/shared/interfaces/search.interface'
|
||||
import { SongResult } from '../../../../src-shared/interfaces/search.interface'
|
||||
import { SearchService } from './search.service'
|
||||
|
||||
// Note: this class prevents event cycles by only emitting events if the checkbox changes
|
||||
@@ -35,7 +35,7 @@ export class SelectionService {
|
||||
}
|
||||
|
||||
getSelectedResults() {
|
||||
return this.searchResults.filter(result => this.selections[result.id] == true)
|
||||
return this.searchResults.filter(result => this.selections[result.id] === true)
|
||||
}
|
||||
|
||||
onSelectAllChanged(callback: (selected: boolean) => void) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
import { Settings } from 'src/electron/shared/Settings'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { Settings } from '../../../../src-shared/Settings'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -12,22 +11,20 @@ export class SettingsService {
|
||||
private settings: Settings
|
||||
private currentThemeLink: HTMLLinkElement
|
||||
|
||||
constructor(private electronService: ElectronService) { }
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = await this.electronService.invoke('get-settings', undefined)
|
||||
if (this.settings.theme != this.builtinThemes[0]) {
|
||||
this.settings = await window.electron.invoke.getSettings()
|
||||
if (this.settings.theme !== this.builtinThemes[0]) {
|
||||
this.changeTheme(this.settings.theme)
|
||||
}
|
||||
}
|
||||
|
||||
saveSettings() {
|
||||
this.electronService.sendIPC('set-settings', this.settings)
|
||||
window.electron.emit.setSettings(this.settings)
|
||||
}
|
||||
|
||||
changeTheme(theme: string) {
|
||||
if (this.currentThemeLink != undefined) this.currentThemeLink.remove()
|
||||
if (theme == 'Default') { return }
|
||||
if (this.currentThemeLink !== undefined) this.currentThemeLink.remove()
|
||||
if (theme === 'Default') { return }
|
||||
|
||||
const link = document.createElement('link')
|
||||
link.type = 'text/css'
|
||||
@@ -36,21 +33,11 @@ export class SettingsService {
|
||||
this.currentThemeLink = document.head.appendChild(link)
|
||||
}
|
||||
|
||||
async getCacheSize() {
|
||||
return this.electronService.defaultSession.getCacheSize()
|
||||
}
|
||||
|
||||
async clearCache() {
|
||||
this.saveSettings()
|
||||
await this.electronService.defaultSession.clearCache()
|
||||
await this.electronService.invoke('clear-cache', undefined)
|
||||
}
|
||||
|
||||
// Individual getters/setters
|
||||
get libraryDirectory() {
|
||||
return this.settings.libraryPath
|
||||
}
|
||||
set libraryDirectory(newValue: string) {
|
||||
set libraryDirectory(newValue: string | undefined) {
|
||||
this.settings.libraryPath = newValue
|
||||
this.saveSettings()
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ export class TabPersistStrategy extends RouteReuseStrategy {
|
||||
}
|
||||
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle) {
|
||||
if (route.data.shouldReuse) {
|
||||
this.handles[route.routeConfig.path] = handle
|
||||
this.handles[route.routeConfig!.path!] = handle
|
||||
}
|
||||
}
|
||||
shouldAttach(route: ActivatedRouteSnapshot) {
|
||||
return !!route.routeConfig && !!this.handles[route.routeConfig.path]
|
||||
return !!route.routeConfig && !!this.handles[route.routeConfig!.path!]
|
||||
}
|
||||
retrieve(route: ActivatedRouteSnapshot) {
|
||||
if (!route.routeConfig) return null
|
||||
return this.handles[route.routeConfig.path]
|
||||
return this.handles[route.routeConfig!.path!]
|
||||
}
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot) {
|
||||
return future.data.shouldReuse || false
|
||||
|
||||
Reference in New Issue
Block a user