mirror of
https://github.com/dev-claw/vripper-project.git
synced 2026-08-19 08:35:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fd70a821b | ||
|
|
6e9c912118 | ||
|
|
19a98ea056 | ||
|
|
229bc46227 | ||
|
|
374946c6f2 | ||
|
|
f8eccfb4ad |
@@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## [1.6.3] - 2019-09-18
|
||||
### Changed
|
||||
- Better multithread management
|
||||
- Fix partial state UI
|
||||
|
||||
## [1.6.2] - 2019-09-17
|
||||
### Changed
|
||||
- Rework UI colors
|
||||
- Fix scan input bug
|
||||
|
||||
## [1.6.1] - 2019-09-16
|
||||
### Changed
|
||||
- Rework UI
|
||||
- Fix clipboard monitoring
|
||||
|
||||
## [1.6.0] - 2019-09-15
|
||||
### Changed
|
||||
- Rework the UI
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.3</version>
|
||||
<packaging>pom</packaging>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-electron",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-electron",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.3",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"author": "",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.3</version>
|
||||
</parent>
|
||||
<artifactId>vripper-electron</artifactId>
|
||||
<name>vripper-electron</name>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.3</version>
|
||||
</parent>
|
||||
<artifactId>vripper-server</artifactId>
|
||||
<name>vripper-server</name>
|
||||
|
||||
@@ -34,12 +34,14 @@ public class DownloadQ {
|
||||
@Getter
|
||||
private boolean notPauseQ = true;
|
||||
|
||||
public synchronized void put(Image image) throws InterruptedException {
|
||||
logger.info(String.format("Enqueuing a job for %s", image.getUrl()));
|
||||
image.init();
|
||||
DownloadJob downloadJob = new DownloadJob(image);
|
||||
downloadQ.put(downloadJob);
|
||||
appStateService.newDownloadJob(downloadJob);
|
||||
public void put(Image image) throws InterruptedException {
|
||||
synchronized (appStateService) {
|
||||
logger.info(String.format("Enqueuing a job for %s", image.getUrl()));
|
||||
image.init();
|
||||
DownloadJob downloadJob = new DownloadJob(image);
|
||||
downloadQ.put(downloadJob);
|
||||
appStateService.newDownloadJob(downloadJob);
|
||||
}
|
||||
}
|
||||
|
||||
public DownloadJob take() throws InterruptedException {
|
||||
@@ -48,69 +50,18 @@ public class DownloadQ {
|
||||
return downloadJob;
|
||||
}
|
||||
|
||||
public void enqueue(Post post) throws InterruptedException {
|
||||
public synchronized void enqueue(Post post) throws InterruptedException {
|
||||
for (Image image : post.getImages()) {
|
||||
put(image);
|
||||
}
|
||||
}
|
||||
|
||||
public void restart(String postId) throws InterruptedException {
|
||||
if (appStateService.getRunningPosts().get(postId) != null && appStateService.getRunningPosts().get(postId).get() > 0) {
|
||||
logger.warn(String.format("Cannot restart, jobs are currently running for post id %s", postId));
|
||||
return;
|
||||
}
|
||||
List<Image> images = appStateService.getPost(postId)
|
||||
.getImages()
|
||||
.stream()
|
||||
.filter(e -> !e.getStatus().equals(Image.Status.COMPLETE))
|
||||
.collect(Collectors.toList());
|
||||
if (images.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
appStateService.getPost(postId).setStatus(Post.Status.PENDING);
|
||||
logger.info(String.format("Restarting %d jobs for post id %s", images.size(), postId));
|
||||
for (Image image : images) {
|
||||
put(image);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeScheduled(Image image) {
|
||||
image.setStatus(Image.Status.STOPPED);
|
||||
logger.info(String.format("Removing scheduled job for %s", image.getUrl()));
|
||||
|
||||
Iterator<DownloadJob> iterator = downloadQ.iterator();
|
||||
boolean removed = false;
|
||||
while(iterator.hasNext()) {
|
||||
DownloadJob next = iterator.next();
|
||||
if(next.getImage().getPostId().equals(image.getPostId())) {
|
||||
iterator.remove();
|
||||
appStateService.doneDownloadJob(image);
|
||||
logger.info(String.format("Scheduled job for %s is removed", image.getUrl()));
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!removed) {
|
||||
logger.warn(String.format("Job for %s does not exist", image.getUrl()));
|
||||
}
|
||||
|
||||
image.cleanup();
|
||||
}
|
||||
|
||||
public void removeRunning(String postId) {
|
||||
logger.info(String.format("Interrupting running jobs for post id %s", postId));
|
||||
executionService.stop(postId);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void stop(String postId) {
|
||||
try {
|
||||
if (FINISHED.contains(appStateService.getPost(postId).getStatus())) {
|
||||
synchronized (appStateService) {
|
||||
if (appStateService.getRunningPosts().get(postId) != null && appStateService.getRunningPosts().get(postId).get() > 0) {
|
||||
logger.warn(String.format("Cannot restart, jobs are currently running for post id %s", postId));
|
||||
return;
|
||||
}
|
||||
notPauseQ = false;
|
||||
appStateService.getPost(postId).setStatus(Post.Status.STOPPED);
|
||||
List<Image> images = appStateService.getPost(postId)
|
||||
.getImages()
|
||||
.stream()
|
||||
@@ -119,9 +70,66 @@ public class DownloadQ {
|
||||
if (images.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
logger.info(String.format("Stopping %d jobs for post id %s", images.size(), postId));
|
||||
images.forEach(image -> removeScheduled(image));
|
||||
removeRunning(postId);
|
||||
appStateService.getPost(postId).setStatus(Post.Status.PENDING);
|
||||
logger.info(String.format("Restarting %d jobs for post id %s", images.size(), postId));
|
||||
for (Image image : images) {
|
||||
put(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeScheduled(Image image) {
|
||||
synchronized (appStateService) {
|
||||
image.setStatus(Image.Status.STOPPED);
|
||||
logger.info(String.format("Removing scheduled job for %s", image.getUrl()));
|
||||
|
||||
Iterator<DownloadJob> iterator = downloadQ.iterator();
|
||||
boolean removed = false;
|
||||
while (iterator.hasNext()) {
|
||||
DownloadJob next = iterator.next();
|
||||
if (next.getImage().getPostId().equals(image.getPostId())) {
|
||||
iterator.remove();
|
||||
appStateService.doneDownloadJob(image);
|
||||
logger.info(String.format("Scheduled job for %s is removed", image.getUrl()));
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!removed) {
|
||||
logger.warn(String.format("Job for %s does not exist", image.getUrl()));
|
||||
}
|
||||
|
||||
image.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRunning(String postId) {
|
||||
logger.info(String.format("Interrupting running jobs for post id %s", postId));
|
||||
executionService.stop(postId);
|
||||
}
|
||||
|
||||
|
||||
public void stop(String postId) {
|
||||
try {
|
||||
synchronized (appStateService) {
|
||||
if (FINISHED.contains(appStateService.getPost(postId).getStatus())) {
|
||||
return;
|
||||
}
|
||||
notPauseQ = false;
|
||||
appStateService.getPost(postId).setStatus(Post.Status.STOPPED);
|
||||
List<Image> images = appStateService.getPost(postId)
|
||||
.getImages()
|
||||
.stream()
|
||||
.filter(e -> !e.getStatus().equals(Image.Status.COMPLETE))
|
||||
.collect(Collectors.toList());
|
||||
if (images.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
logger.info(String.format("Stopping %d jobs for post id %s", images.size(), postId));
|
||||
images.forEach(image -> removeScheduled(image));
|
||||
removeRunning(postId);
|
||||
}
|
||||
} finally {
|
||||
notPauseQ = true;
|
||||
}
|
||||
@@ -131,14 +139,18 @@ public class DownloadQ {
|
||||
return downloadQ.size();
|
||||
}
|
||||
|
||||
public synchronized void stopAll() {
|
||||
appStateService.getCurrentPosts().values().stream().map(Post::getPostId).forEach(this::stop);
|
||||
public void stopAll() {
|
||||
synchronized (appStateService) {
|
||||
appStateService.getCurrentPosts().values().stream().map(Post::getPostId).forEach(this::stop);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void restartAll() throws InterruptedException {
|
||||
for (Post post : appStateService.getCurrentPosts().values()) {
|
||||
String postId = post.getPostId();
|
||||
restart(postId);
|
||||
public void restartAll() throws InterruptedException {
|
||||
synchronized (appStateService) {
|
||||
for (Post post : appStateService.getCurrentPosts().values()) {
|
||||
String postId = post.getPostId();
|
||||
restart(postId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-28
@@ -34,9 +34,10 @@ public class SettingsRestEndpoint {
|
||||
@PostMapping("/settings/theme")
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public AppSettingsService.Theme postTheme(@RequestBody AppSettingsService.Theme theme) {
|
||||
|
||||
this.settings.setTheme(theme);
|
||||
return settings.getTheme();
|
||||
synchronized (this.settings) {
|
||||
this.settings.setTheme(theme);
|
||||
return settings.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/settings/theme")
|
||||
@@ -49,33 +50,35 @@ public class SettingsRestEndpoint {
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public ResponseEntity postSettings(@RequestBody AppSettingsService.Settings settings) throws Exception {
|
||||
|
||||
try {
|
||||
this.settings.check(settings);
|
||||
} catch (ValidationException e) {
|
||||
return new ResponseEntity(new Response(e.getMessage()), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
this.settings.setDownloadPath(settings.getDownloadPath());
|
||||
this.settings.setMaxThreads(settings.getMaxThreads());
|
||||
this.settings.setAutoStart(settings.isAutoStart());
|
||||
this.settings.setVLogin(settings.isVLogin());
|
||||
|
||||
if(settings.isVLogin()) {
|
||||
this.settings.setVUsername(settings.getVUsername());
|
||||
if (!this.settings.getVPassword().equals(settings.getVPassword())) {
|
||||
this.settings.setVPassword(settings.getVPassword());
|
||||
synchronized (this.settings) {
|
||||
try {
|
||||
this.settings.check(settings);
|
||||
} catch (ValidationException e) {
|
||||
return new ResponseEntity(new Response(e.getMessage()), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
this.settings.setVThanks(settings.isVThanks());
|
||||
} else {
|
||||
this.settings.setVUsername("");
|
||||
this.settings.setVPassword("");
|
||||
this.settings.setVThanks(false);
|
||||
this.settings.setDownloadPath(settings.getDownloadPath());
|
||||
this.settings.setMaxThreads(settings.getMaxThreads());
|
||||
this.settings.setAutoStart(settings.isAutoStart());
|
||||
this.settings.setVLogin(settings.isVLogin());
|
||||
|
||||
if (settings.isVLogin()) {
|
||||
this.settings.setVUsername(settings.getVUsername());
|
||||
if (!this.settings.getVPassword().equals(settings.getVPassword())) {
|
||||
this.settings.setVPassword(settings.getVPassword());
|
||||
}
|
||||
this.settings.setVThanks(settings.isVThanks());
|
||||
} else {
|
||||
this.settings.setVUsername("");
|
||||
this.settings.setVPassword("");
|
||||
this.settings.setVThanks(false);
|
||||
}
|
||||
this.settings.setDesktopClipboard(settings.isDesktopClipboard());
|
||||
this.settings.setForceOrder(settings.isForceOrder());
|
||||
|
||||
this.settings.save();
|
||||
|
||||
vipergirlsAuthService.authenticate();
|
||||
}
|
||||
this.settings.setDesktopClipboard(settings.isDesktopClipboard());
|
||||
this.settings.setForceOrder(settings.isForceOrder());
|
||||
|
||||
this.settings.save();
|
||||
|
||||
vipergirlsAuthService.authenticate();
|
||||
return ResponseEntity.ok(getSettings());
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-ui",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-ui",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.3",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.6.3</version>
|
||||
</parent>
|
||||
<artifactId>vripper-ui</artifactId>
|
||||
<name>vripper-ui</name>
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
// mixin name will be used in main style.scss
|
||||
@mixin app-component-theme($theme) {
|
||||
|
||||
// retrieve variables from theme
|
||||
// (all possible variables, use only what you really need)
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, accent);
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
$background: map-get($theme, background);
|
||||
|
||||
// all of these variables contain many additional variables
|
||||
|
||||
button.add-button {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import { RemoveAllResponse } from './common/remove-all-response.model';
|
||||
import { ServerService } from './server-service';
|
||||
import { ConfirmDialogComponent } from './common/confirmation-component/confirmation-dialog';
|
||||
import { filter, flatMap } from 'rxjs/operators';
|
||||
import { ScanComponent } from './scan/scan.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -52,12 +51,7 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
|
||||
scan() {
|
||||
const dialogRef = this.dialog.open(ScanComponent, {
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
maxWidth: '100vw',
|
||||
maxHeight: '100vh'
|
||||
});
|
||||
this.appService.scan();
|
||||
}
|
||||
|
||||
openSettings(): void {
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable, Renderer2 } from '@angular/core';
|
||||
import { Injectable, Renderer2, NgZone } from '@angular/core';
|
||||
import { ServerService } from './server-service';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { ScanComponent } from './scan/scan.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { BreakpointState, Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
|
||||
constructor(private httpClient: HttpClient, private serverService: ServerService) {}
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private serverService: ServerService,
|
||||
public dialog: MatDialog,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
) {}
|
||||
|
||||
darkTheme = false;
|
||||
_renderer: Renderer2;
|
||||
@@ -14,6 +22,9 @@ export class AppService {
|
||||
this._renderer = renderer;
|
||||
}
|
||||
|
||||
isExtraSmall: Observable<BreakpointState> = this.breakpointObserver.observe(Breakpoints.XSmall);
|
||||
isScanOpen = false;
|
||||
|
||||
updateTheme(darkTheme: boolean) {
|
||||
this.darkTheme = darkTheme;
|
||||
if (this.darkTheme) {
|
||||
@@ -23,20 +34,46 @@ export class AppService {
|
||||
this._renderer.addClass(document.body, 'light-theme');
|
||||
this._renderer.removeClass(document.body, 'dark-theme');
|
||||
}
|
||||
this.httpClient.post<Theme>(this.serverService.baseUrl + '/settings/theme', {
|
||||
darkTheme: this.darkTheme
|
||||
}).subscribe();
|
||||
this.httpClient
|
||||
.post<Theme>(this.serverService.baseUrl + '/settings/theme', {
|
||||
darkTheme: this.darkTheme
|
||||
})
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
loadTheme() {
|
||||
return this.httpClient
|
||||
.get<Theme>(this.serverService.baseUrl + '/settings/theme')
|
||||
.pipe(
|
||||
tap(theme => this.updateTheme(theme.darkTheme))
|
||||
);
|
||||
.get<Theme>(this.serverService.baseUrl + '/settings/theme')
|
||||
.pipe(tap(theme => this.updateTheme(theme.darkTheme)));
|
||||
}
|
||||
|
||||
scan(url?: string) {
|
||||
|
||||
const scanDialog = this.dialog.open(ScanComponent, {
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
maxWidth: '100vw',
|
||||
maxHeight: '100vh',
|
||||
data: {url: url}
|
||||
});
|
||||
|
||||
const smallDialogSubscription = this.isExtraSmall.subscribe(result => {
|
||||
if (result.matches) {
|
||||
scanDialog.updateSize('100%', '100%');
|
||||
} else {
|
||||
scanDialog.updateSize('70%', '70%');
|
||||
}
|
||||
});
|
||||
|
||||
scanDialog.afterOpened().subscribe(() => this.isScanOpen = true);
|
||||
|
||||
scanDialog.afterClosed().subscribe(() => {
|
||||
smallDialogSubscription.unsubscribe();
|
||||
this.isScanOpen = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface Theme {
|
||||
darkTheme: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { AppService } from './../app.service';
|
||||
import { ElectronService } from 'ngx-electron';
|
||||
import { ClipboardService } from './../clipboard.service';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { Component, OnInit, OnDestroy, NgZone } from '@angular/core';
|
||||
import { MatDialog, MatSnackBar } from '@angular/material';
|
||||
import { WsConnectionService } from '../ws-connection.service';
|
||||
import { WsHandler } from '../ws-handler';
|
||||
import { Subscription } from 'rxjs';
|
||||
@@ -23,7 +24,10 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
private clipboardService: ClipboardService,
|
||||
public dialog: MatDialog,
|
||||
public electronService: ElectronService,
|
||||
private wsConnectionService: WsConnectionService
|
||||
private wsConnectionService: WsConnectionService,
|
||||
private appService: AppService,
|
||||
private _snackBar: MatSnackBar,
|
||||
private ngZone: NgZone
|
||||
) {
|
||||
this.websocketHandlerPromise = this.wsConnectionService.getConnection();
|
||||
}
|
||||
@@ -32,13 +36,15 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit() {
|
||||
this.clipboardService.links.subscribe(e => {
|
||||
// if (this.loading) {
|
||||
// this._snackBar.open(e + ' was not processed, the app is beasy parsing another thread', null, {
|
||||
// duration: 5000
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// this.processUrl(e);
|
||||
this.ngZone.run(() => {
|
||||
if (this.appService.isScanOpen) {
|
||||
this._snackBar.open(e + ' was not processed, the app is busy parsing another thread', null, {
|
||||
duration: 5000
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.appService.scan(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@ export class MultiPostComponent implements OnInit, OnDestroy {
|
||||
loading = true;
|
||||
|
||||
constructor(
|
||||
// public dialogRef: MatDialogRef<MultiPostComponent>,
|
||||
// @Inject(MAT_DIALOG_DATA) public data: { threadId: string; threadUrl: string },
|
||||
private ngZone: NgZone,
|
||||
private _snackBar: MatSnackBar,
|
||||
private wsConnectionService: WsConnectionService,
|
||||
@@ -39,7 +37,6 @@ export class MultiPostComponent implements OnInit, OnDestroy {
|
||||
private serverService: ServerService
|
||||
) {
|
||||
this.websocketHandlerPromise = this.wsConnectionService.getConnection();
|
||||
// this.threadId = data.threadId;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -137,12 +134,6 @@ export class MultiPostComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
// close() {
|
||||
// this.ngZone.run(() => {
|
||||
// this.dialogRef.close();
|
||||
// });
|
||||
// }
|
||||
|
||||
submit() {
|
||||
const data = (<VRPostParse[]>this.gridOptions.api.getSelectedRows()).map(e => ({
|
||||
postId: e.postId,
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
<div class="container" style="height: 100%; background-color: snow">
|
||||
<div class="container" style="height: 100%; background-color: white">
|
||||
<div
|
||||
[ngClass]="{
|
||||
error: postDetails.status === 'ERROR',
|
||||
stopped: postDetails.status === 'STOPPED',
|
||||
pending: postDetails.status === 'PENDING'
|
||||
}"
|
||||
class="progress-bar-back"
|
||||
style="position: relative; height: 100%;"
|
||||
>
|
||||
<div
|
||||
[ngClass]="{
|
||||
complete: postDetails.status === 'COMPLETE',
|
||||
downloading: postDetails.status === 'DOWNLOADING'
|
||||
}"
|
||||
[style.width]="trunc(postDetails.progress) + '%'"
|
||||
class="progress-bar"
|
||||
style="position: absolute; height: 100%; width: 100%"
|
||||
></div>
|
||||
|
||||
<div
|
||||
class="progress-foreground"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-between"
|
||||
style="position: absolute; background-color: transparent; width: 100%; height: 100%; padding: 0 8px;"
|
||||
style="background-color: transparent; width: 100%; height: 100%;"
|
||||
>
|
||||
<span
|
||||
><a (click)="goTo()" href="javascript:void(0)" style="color: rgba(0, 0, 0, 0.87);">{{
|
||||
postDetails.url
|
||||
}}</a></span
|
||||
>
|
||||
<span class="progress-percentage">{{ trunc(postDetails.progress) + '%' }}</span>
|
||||
<div class="progress-bar" style="position: absolute; width: 100%; top: 37px; padding: 0 20px">
|
||||
<mat-progress-bar [value]="postDetails.progress" class="example-margin" color="primary" mode="determinate">
|
||||
</mat-progress-bar>
|
||||
</div>
|
||||
<span fxLayout="row">
|
||||
<span style="padding-left: 20px"
|
||||
><a (click)="goTo()" href="javascript:void(0)" style="color: rgba(0, 0, 0, 0.87);">{{
|
||||
postDetails.url
|
||||
}}</a></span
|
||||
>
|
||||
<span class="filler" fxFlex="grow"></span>
|
||||
</span>
|
||||
<span class="progress-percentage" style="padding-right: 20px">{{ trunc(postDetails.progress) + '%' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.progress-bar-back {
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
.progress-bar {
|
||||
transition: width 0.5s, background-color 0.5s;
|
||||
}
|
||||
.complete {
|
||||
background-color: #3865a3;
|
||||
}
|
||||
.pending {
|
||||
background-color: white;
|
||||
}
|
||||
.error {
|
||||
background-color: #eb6060;
|
||||
}
|
||||
.downloading {
|
||||
background-color: #87a2c7;
|
||||
}
|
||||
.stopped {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin post-detail-renderer-component-theme($theme) {
|
||||
$blue: mat-palette($mat-blue);
|
||||
|
||||
.progress-bar .mat-progress-bar-fill::after {
|
||||
background-color: mat-color($blue, 300);
|
||||
}
|
||||
|
||||
.progress-bar .mat-progress-bar-buffer {
|
||||
background-color: mat-color($blue, 100);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { ICellRendererParams } from 'ag-grid-community';
|
||||
import { ElectronService } from 'ngx-electron';
|
||||
|
||||
@Component({
|
||||
selector: 'app-progress-cell',
|
||||
selector: 'app-details-cell',
|
||||
templateUrl: 'post-details-progress.component.html',
|
||||
styleUrls: ['post-details-progress.component.scss']
|
||||
})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<div class="container" style="height: 100%; background-color: snow">
|
||||
<div class="container" style="height: 100%; background-color: white">
|
||||
<div
|
||||
[ngClass]="{
|
||||
'pending-back': postState.status === 'PENDING'
|
||||
'error-back': postState.status === 'ERROR',
|
||||
'downloading-back': postState.status === 'DOWNLOADING' || postState.status === 'PARTIAL',
|
||||
'complete-back': postState.status === 'COMPLETE'
|
||||
}"
|
||||
class="progress-bar-back"
|
||||
style="position: relative; height: 100%; max-height: 48px;"
|
||||
@@ -10,9 +12,9 @@
|
||||
class="progress-foreground"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-between"
|
||||
style="position: absolute; background-color: transparent; width: 100%; height: 100%;"
|
||||
style="background-color: transparent; width: 100%; height: 100%;"
|
||||
>
|
||||
<div class="progress-bar" style="position: absolute; width: 100%; top: 37px; padding: 0 50px">
|
||||
<div class="progress-bar" color="accent" style="position: absolute; width: 100%; top: 37px; padding: 0 50px">
|
||||
<mat-progress-bar [value]="postState.progress" class="example-margin" color="primary" mode="determinate">
|
||||
</mat-progress-bar>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
.progress-bar-back {
|
||||
transition: background-color 0.5s;
|
||||
}
|
||||
.pending-back {
|
||||
background-color: snow;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: table;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin post-progress-renderer-component-theme($theme) {
|
||||
$red: mat-palette($mat-red);
|
||||
$grey: mat-palette($mat-grey);
|
||||
$green: mat-palette($mat-green);
|
||||
|
||||
app-progress-cell .progress-bar .mat-progress-bar-fill::after {
|
||||
background-color: mat-color($grey, 300);
|
||||
}
|
||||
|
||||
app-progress-cell .progress-bar .mat-progress-bar-buffer {
|
||||
background-color: mat-color($grey, 100);
|
||||
}
|
||||
|
||||
app-progress-cell .error-back {
|
||||
background-color: mat-color($red, 50);
|
||||
& .progress-bar .mat-progress-bar-fill::after {
|
||||
background-color: mat-color($red, 300);
|
||||
}
|
||||
& .progress-bar .mat-progress-bar-buffer {
|
||||
background-color: mat-color($red, 100);
|
||||
}
|
||||
}
|
||||
|
||||
app-progress-cell .downloading-back {
|
||||
background-color: mat-color($green, 50);
|
||||
& .progress-bar .mat-progress-bar-fill::after {
|
||||
background-color: mat-color($green, 300);
|
||||
}
|
||||
& .progress-bar .mat-progress-bar-buffer {
|
||||
background-color: mat-color($green, 100);
|
||||
}
|
||||
}
|
||||
|
||||
app-progress-cell .complete-back {
|
||||
background-color: mat-color($green, 100);
|
||||
& .progress-bar .mat-progress-bar-fill::after {
|
||||
background-color: mat-color($green, 300);
|
||||
}
|
||||
& .progress-bar .mat-progress-bar-buffer {
|
||||
background-color: mat-color($green, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<h2 class="no-wrap" mat-dialog-title>Scan</h2>
|
||||
</div>
|
||||
<mat-dialog-content fxFlex="grow" fxLayout="column">
|
||||
<div *ngIf="threadId == null">
|
||||
<div *ngIf="!hideScan">
|
||||
<form
|
||||
#f="ngForm"
|
||||
(ngSubmit)="submit(f)"
|
||||
@@ -31,8 +31,8 @@
|
||||
</ng-container>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-dialog-close mat-raised-button>Close</button>
|
||||
<button (click)="addPosts()" *ngIf="multipost != null" color="primary" mat-raised-button type="submit">
|
||||
<button (click)="close()" mat-raised-button>Close</button>
|
||||
<button (click)="addPosts()" *ngIf="threadId != null" color="primary" mat-raised-button type="submit">
|
||||
Download
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, OnInit, NgZone, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit, NgZone, ViewChild, Inject } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { MatSnackBar, MatDialog, MatDialogRef } from '@angular/material';
|
||||
import { MatSnackBar, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { ServerService } from '../server-service';
|
||||
@@ -12,75 +12,101 @@ import { MultiPostComponent } from '../multi-post/multi-post.component';
|
||||
styleUrls: ['./scan.component.scss']
|
||||
})
|
||||
export class ScanComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private ngZone: NgZone,
|
||||
private httpClient: HttpClient,
|
||||
private serverService: ServerService,
|
||||
private _snackBar: MatSnackBar,
|
||||
public dialogRef: MatDialogRef<ScanComponent>,
|
||||
) { }
|
||||
@Inject(MAT_DIALOG_DATA) public data: DialogData
|
||||
) {}
|
||||
|
||||
@ViewChild(MultiPostComponent)
|
||||
multipost: MultiPostComponent;
|
||||
|
||||
input: string;
|
||||
threadId: string;
|
||||
hideScan = false;
|
||||
|
||||
submit(form: NgForm) {
|
||||
this.threadId = null;
|
||||
this.processUrl(this.input, form);
|
||||
this.ngZone.run(() => {
|
||||
this.hideScan = true;
|
||||
this.threadId = null;
|
||||
this.processUrl(this.input, form);
|
||||
});
|
||||
}
|
||||
|
||||
done(done: boolean) {
|
||||
if(done) {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
this.ngZone.run(() => {
|
||||
if (done) {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processUrl(url: string, form?: NgForm) {
|
||||
this.ngZone.run(() => {
|
||||
// this.loading = true;
|
||||
});
|
||||
this.httpClient
|
||||
.post<{ threadId: string, postId: string}>(this.serverService.baseUrl + '/post', { url: url })
|
||||
.pipe(finalize(() => {
|
||||
this.ngZone.run(() => {
|
||||
// this.loading = false;
|
||||
});
|
||||
if (form != null) {
|
||||
form.resetForm();
|
||||
this.input = null;
|
||||
}
|
||||
}))
|
||||
.subscribe(response => {
|
||||
if (response.postId != null) {
|
||||
this.httpClient.post(this.serverService.baseUrl + '/post/add', [response]).subscribe(
|
||||
() => {
|
||||
this._snackBar.open('Adding posts to queue', null, {
|
||||
duration: 5000
|
||||
});
|
||||
},
|
||||
error => {
|
||||
this._snackBar.open(error.error, null, {
|
||||
duration: 5000
|
||||
});
|
||||
.post<{ threadId: string; postId: string }>(this.serverService.baseUrl + '/post', { url: url })
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.ngZone.run(() => {
|
||||
if (form != null) {
|
||||
form.resetForm();
|
||||
this.input = null;
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.threadId = response.threadId;
|
||||
});
|
||||
})
|
||||
)
|
||||
.subscribe(response => {
|
||||
this.ngZone.run(() => {
|
||||
if (response.postId != null) {
|
||||
this.httpClient
|
||||
.post(this.serverService.baseUrl + '/post/add', [response])
|
||||
.pipe(finalize(() => this.dialogRef.close()))
|
||||
.subscribe(
|
||||
() => {
|
||||
this._snackBar.open('Adding posts to queue', null, {
|
||||
duration: 5000
|
||||
});
|
||||
},
|
||||
error => {
|
||||
this._snackBar.open(error.error, null, {
|
||||
duration: 5000
|
||||
});
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.threadId = response.threadId;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addPosts() {
|
||||
if (this.multipost != null) {
|
||||
this.multipost.submit();
|
||||
}
|
||||
this.dialogRef.close();
|
||||
this.ngZone.run(() => {
|
||||
if (this.multipost != null) {
|
||||
this.multipost.submit();
|
||||
}
|
||||
this.dialogRef.close();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.ngZone.run(() => {
|
||||
if (this.data.url != null) {
|
||||
this.hideScan = true;
|
||||
this.processUrl(this.data.url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.ngZone.run(() => {
|
||||
this.dialogRef.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface DialogData {
|
||||
url: string;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
// mixin name will be used in main style.scss
|
||||
@mixin status-bar-component-theme($theme) {
|
||||
|
||||
// retrieve variables from theme
|
||||
// (all possible variables, use only what you really need)
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, accent);
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
// all of these variables contain many additional variables
|
||||
|
||||
.status-bar {
|
||||
|
||||
background-color: mat-color($background, status-bar);
|
||||
color: mat-color($foreground, base);
|
||||
}
|
||||
}
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
.status-bar {
|
||||
background-color: mat-color($background, status-bar);
|
||||
color: mat-color($foreground, base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
.ag-row {
|
||||
// transition: height,transform 0.5s;
|
||||
}
|
||||
|
||||
.ag-header, .ag-icon {
|
||||
.ag-header, .ag-header .ag-icon {
|
||||
|
||||
color: mat-color($foreground, secondary-text) !important;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
@import 'mat-theme.scss';
|
||||
@import 'app/status-bar/status-bar.component.scss.theme.scss';
|
||||
@import 'app/app.component.scss-theme.scss';
|
||||
@import 'app/posts/post-progress.renderer.component.scss-theme.scss';
|
||||
@import 'app/post-detail/post-details-progress.component.scss-theme.scss';
|
||||
@import 'grid-theme.scss';
|
||||
|
||||
@mixin custom-components-theme($theme) {
|
||||
@include status-bar-component-theme($theme);
|
||||
@include app-component-theme($theme);
|
||||
@include post-progress-renderer-component-theme($theme);
|
||||
@include post-detail-renderer-component-theme($theme);
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
|
||||
Reference in New Issue
Block a user