Fixed maximize drag and nested .rar extraction

This commit is contained in:
Geomitron
2020-03-09 10:52:41 -04:00
parent d7659554cc
commit 3a3c2b5476
7 changed files with 110 additions and 32 deletions

View File

@@ -1,4 +1,4 @@
import { Component, ViewChild } from '@angular/core'
import { Component, ViewChild, AfterViewInit } from '@angular/core'
import { ChartSidebarComponent } from './chart-sidebar/chart-sidebar.component'
import { StatusBarComponent } from './status-bar/status-bar.component'
import { SongResult } from 'src/electron/shared/interfaces/search.interface'
@@ -9,7 +9,7 @@ import { ResultTableComponent } from './result-table/result-table.component'
templateUrl: './browse.component.html',
styleUrls: ['./browse.component.scss']
})
export class BrowseComponent {
export class BrowseComponent implements AfterViewInit {
@ViewChild('resultTable', { static: true }) resultTable: ResultTableComponent
@ViewChild('chartSidebar', { static: true }) chartSidebar: ChartSidebarComponent
@@ -17,6 +17,24 @@ export class BrowseComponent {
constructor() { }
ngAfterViewInit() {
const $tableColumn = $('#table-column')
$tableColumn.visibility({
once: false,
continuous: true,
context: $tableColumn,
observeChanges: true,
onUpdate: () => {
let pos = $tableColumn[0].scrollTop + $tableColumn[0].offsetHeight
let max = $tableColumn[0].scrollHeight
if (pos >= max - 5) {
// TODO: load more results (should be debounced or something; wait until results have loaded before sending the request for more)
console.log('UPDATE SCROLL')
}
}
})
}
onResultsUpdated(results: SongResult[]) {
this.resultTable.results = results
this.resultTable.onNewSearch()
@@ -25,4 +43,8 @@ export class BrowseComponent {
this.statusBar.resultCount = results.length
this.statusBar.selectedResults = []
}
loadMoreResults() {
// TODO: use the same query as the current search, but append more results if there are any more to be viewed
}
}

View File

@@ -172,7 +172,7 @@ export class ChartSidebarComponent {
this.selectedVersion.versionID, {
avTagName: this.selectedVersion.avTagName,
artist: this.songResult.artist,
charter: this.selectedVersion.charters,
charter: this.selectedVersion.charters, //TODO: get the charter name associated with this particular version
links: JSON.parse(this.selectedVersion.downloadLink)
})
}

View File

@@ -6,7 +6,7 @@
<div class="right menu">
<a class="item traffic-light" (click)="minimize()"><i class="minus icon"></i></a>
<a class="item traffic-light" (click)="maximize()"><i class="icon window" [ngClass]="isMaximized ? 'restore' : 'maximize'"></i></a>
<a class="item traffic-light" (click)="toggleMaximized()"><i class="icon window" [ngClass]="isMaximized ? 'restore' : 'maximize'"></i></a>
<a class="item traffic-light" (click)="close()"><i class="x icon"></i></a>
</div>
</div>

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, ChangeDetectorRef } from '@angular/core'
import { ElectronService } from '../../core/services/electron.service'
@Component({
@@ -10,17 +10,25 @@ export class ToolbarComponent implements OnInit {
isMaximized: boolean
constructor(private electronService: ElectronService) { }
constructor(private electronService: ElectronService, private ref: ChangeDetectorRef) { }
ngOnInit() {
this.isMaximized = this.electronService.currentWindow.isMaximized()
this.electronService.currentWindow.on('unmaximize', () => {
this.isMaximized = false
this.ref.detectChanges()
})
this.electronService.currentWindow.on('maximize', () => {
this.isMaximized = true
this.ref.detectChanges()
})
}
minimize() {
this.electronService.currentWindow.minimize()
}
maximize() {
toggleMaximized() {
if (this.isMaximized) {
this.electronService.currentWindow.restore()
} else {

View File

@@ -1,13 +1,13 @@
import { exists as _exists, mkdir as _mkdir, readFile as _readFile, writeFile as _writeFile } from 'fs'
import * as fs from 'fs'
import { dataPath, tempPath, themesPath, settingsPath } from '../shared/Paths'
import { promisify } from 'util'
import { IPCInvokeHandler, IPCEmitHandler } from '../shared/IPCHandler'
import { defaultSettings, Settings } from '../shared/Settings'
const exists = promisify(_exists)
const mkdir = promisify(_mkdir)
const readFile = promisify(_readFile)
const writeFile = promisify(_writeFile)
const exists = promisify(fs.exists)
const mkdir = promisify(fs.mkdir)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
let settings: Settings

View File

@@ -1,21 +1,20 @@
import { DownloadError } from './FileDownloader'
import { readdir as _readdir, unlink as _unlink, lstat as _lstat, copyFile as _copyFile,
rmdir as _rmdir, access as _access, mkdir as _mkdir, constants } from 'fs'
import * as fs from 'fs'
import { promisify } from 'util'
import { join, extname } from 'path'
import * as node7z from 'node-7z'
import * as zipBin from '7zip-bin'
import * as unrarjs from 'node-unrar-js'
import { getSettingsHandler } from '../SettingsHandler.ipc'
import { extractRar } from './RarExtractor'
const getSettings = getSettingsHandler.getSettings
const readdir = promisify(_readdir)
const unlink = promisify(_unlink)
const lstat = promisify(_lstat)
const copyFile = promisify(_copyFile)
const rmdir = promisify(_rmdir)
const access = promisify(_access)
const mkdir = promisify(_mkdir)
const readdir = promisify(fs.readdir)
const unlink = promisify(fs.unlink)
const lstat = promisify(fs.lstat)
const copyFile = promisify(fs.copyFile)
const rmdir = promisify(fs.rmdir)
const access = promisify(fs.access)
const mkdir = promisify(fs.mkdir)
type EventCallback = {
'extract': (filename: string) => void
@@ -47,7 +46,7 @@ export class FileExtractor {
this.libraryFolder = getSettings().libraryPath
const files = await readdir(this.sourceFolder)
if (this.isArchive) {
this.extract(files[0])
this.extract(files[0], extname(files[0]) == '.rar')
} else {
this.transfer()
}
@@ -56,19 +55,24 @@ export class FileExtractor {
/**
* Extracts the file at `filename` to `this.sourceFolder`.
*/
private extract(filename: string) {
private async extract(filename: string, useRarExtractor: boolean) {
await new Promise<void>(resolve => setTimeout(() => resolve(), 100)) // Wait for filesystem to process downloaded file...
if (this.wasCanceled) { return } // CANCEL POINT
this.callbacks.extract(filename)
const source = join(this.sourceFolder, filename)
if (extname(filename) == '.rar') {
if (useRarExtractor) {
// Use node-unrar-js to extract the archive
try {
let extractor = unrarjs.createExtractorFromFile(source, this.sourceFolder)
extractor.extractAll()
await extractRar(source, this.sourceFolder)
} catch (err) {
this.callbacks.error({ header: 'Extract Failed.', body: `Unable to extract [${filename}]: ${err.name}` }, () => this.extract(filename))
this.callbacks.error({
header: 'Extract Failed.',
body: `Unable to extract [${filename}]: ${err}`
},
() => this.extract(filename, extname(filename) == '.rar')
)
return
}
this.transfer(source)
@@ -82,12 +86,17 @@ export class FileExtractor {
this.callbacks.extractProgress(progress.percent, progress.fileCount)
})
stream.on('error', (err: Error) => {
this.callbacks.error({ header: 'Extract Failed.', body: `Unable to extract [${filename}]: ${err.name}` }, () => this.extract(filename))
let extractErrorOccured = false
stream.on('error', () => {
extractErrorOccured = true
console.log(`Failed to extract [${filename}], retrying with .rar extractor...`)
this.extract(filename, true)
})
stream.on('end', () => {
if (!extractErrorOccured) {
this.transfer(source)
}
})
}
@@ -104,7 +113,7 @@ export class FileExtractor {
const destinationFolder = join(this.libraryFolder, this.destinationFolderName)
this.callbacks.transfer(destinationFolder)
try {
await access(destinationFolder, constants.F_OK)
await access(destinationFolder, fs.constants.F_OK)
} catch (e) {
await mkdir(destinationFolder)
}

View File

@@ -0,0 +1,39 @@
import * as fs from 'fs'
import { join } from 'path'
import * as unrarjs from 'node-unrar-js'
import { promisify } from 'util'
const mkdir = promisify(fs.mkdir)
/**
* Extracts the archive at `sourceFile` to a new folder in `destinationFolder`. Throws an error when this fails.
*/
export async function extractRar(sourceFile: string, destinationFolder: string) {
const extractor = unrarjs.createExtractorFromFile(sourceFile, destinationFolder)
const fileList = extractor.getFileList()
if (fileList[0].state != 'FAIL') {
// Create directories for nested archives (because unrarjs didn't feel like handling that automatically)
const headers = fileList[1].fileHeaders
for (const header of headers) {
if (header.flags.directory) {
try {
await mkdir(join(destinationFolder, header.name), { recursive: true })
} catch (e) {
throw new Error(`Failed to extract directory: ${e}`)
}
}
}
} else {
console.log('Warning: failed to read .rar files: ', fileList[0].reason, fileList[0].msg)
}
// Extract archive
const extractResult = extractor.extractAll()
if (extractResult[0].state == 'FAIL') {
throw new Error(`${extractResult[0].reason}: ${extractResult[0].msg}`)
}
}