Downloads UI is more mobile friendly (#905)

This commit is contained in:
Isaac Abadi
2023-05-21 19:21:38 -06:00
parent f57263d137
commit 03359940ff
4 changed files with 116 additions and 55 deletions

View File

@@ -52,20 +52,23 @@
<!-- Actions Column -->
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
<mat-cell *matCellDef="let element">
<div>
<ng-container *ngIf="!element.finished">
<button (click)="pauseDownload(element.uid)" *ngIf="!element.paused || !element.finished_step" [disabled]="element.paused && !element.finished_step" mat-icon-button matTooltip="Pause" i18n-matTooltip="Pause"><mat-spinner [diameter]="28" *ngIf="element.paused && !element.finished_step" class="icon-button-spinner"></mat-spinner><mat-icon>pause</mat-icon></button>
<button (click)="resumeDownload(element.uid)" *ngIf="element.paused && element.finished_step" mat-icon-button matTooltip="Resume" i18n-matTooltip="Resume"><mat-icon>play_arrow</mat-icon></button>
<button *ngIf="false && !element.paused" (click)="cancelDownload(element.uid)" mat-icon-button matTooltip="Cancel" i18n-matTooltip="Cancel"><mat-icon>cancel</mat-icon></button>
<mat-header-cell *matHeaderCellDef [ngStyle]="{flex: innerWidth < 800 ? 1 : 2}"> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
<mat-cell *matCellDef="let element" [ngStyle]="{flex: innerWidth < 800 ? 1 : 2}">
<div *ngIf="!uids && innerWidth >= 800">
<ng-container *ngFor="let downloadAction of downloadActions">
<button *ngIf="downloadAction.show(element)" (click)="downloadAction.action(element)" [matTooltip]="downloadAction.tooltip" mat-icon-button><mat-icon>{{downloadAction.icon}}</mat-icon></button>
</ng-container>
<ng-container *ngIf="element.finished">
<button *ngIf="!element.error" (click)="watchContent(element)" mat-icon-button matTooltip="Watch content" i18n-matTooltip="Watch content"><mat-icon>smart_display</mat-icon></button>
<button *ngIf="element.error" (click)="showError(element)" mat-icon-button matTooltip="Show error" i18n-matTooltip="Show error"><mat-icon>warning</mat-icon></button>
<button (click)="restartDownload(element.uid)" mat-icon-button matTooltip="Restart" i18n-matTooltip="Restart"><mat-icon>restart_alt</mat-icon></button>
</ng-container>
<button *ngIf="element.finished || element.paused" (click)="clearDownload(element.uid)" mat-icon-button matTooltip="Clear" i18n-matTooltip="Clear"><mat-icon>delete</mat-icon></button>
</div>
<div *ngIf="uids || innerWidth < 800">
<button [matMenuTriggerFor]="download_actions" mat-icon-button><mat-icon>more_vert</mat-icon></button>
<mat-menu #download_actions="matMenu">
<ng-container *ngFor="let downloadAction of downloadActions">
<button *ngIf="downloadAction.show(element)" (click)="downloadAction.action(element)" mat-menu-item>
<mat-icon>{{downloadAction.icon}}</mat-icon>
<span>{{downloadAction.tooltip}}</span>
</button>
</ng-container>
</mat-menu>
</div>
</mat-cell>
</ng-container>
@@ -80,9 +83,9 @@
</mat-paginator>
</div>
<div *ngIf="!uids" class="downloads-action-button-div">
<button [disabled]="!running_download_exists" mat-stroked-button (click)="pauseAllDownloads()"><ng-container i18n="Pause all downloads">Pause all downloads</ng-container></button>
<button style="margin-left: 10px;" [disabled]="!paused_download_exists" mat-stroked-button (click)="resumeAllDownloads()"><ng-container i18n="Resume all downloads">Resume all downloads</ng-container></button>
<button color="warn" style="margin-left: 10px;" mat-stroked-button (click)="clearDownloadsByType()"><ng-container i18n="Clear downloads">Clear downloads</ng-container></button>
<button class="downloads-action-button" [disabled]="!running_download_exists" mat-stroked-button (click)="pauseAllDownloads()"><ng-container i18n="Pause all downloads">Pause all downloads</ng-container></button>
<button class="downloads-action-button" [disabled]="!paused_download_exists" mat-stroked-button (click)="resumeAllDownloads()"><ng-container i18n="Resume all downloads">Resume all downloads</ng-container></button>
<button class="downloads-action-button" color="warn" mat-stroked-button (click)="clearDownloadsByType()"><ng-container i18n="Clear downloads">Clear downloads</ng-container></button>
</div>
</div>

View File

@@ -15,10 +15,14 @@ mat-header-cell, mat-cell {
}
.downloads-action-button-div {
margin-top: 10px;
margin-left: 5px;
}
.downloads-action-button {
margin-top: 10px;
margin-right: 10px;
}
.rounded-top {
border-radius: 16px 16px 0px 0px !important;
}

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy, ViewChild, Input, EventEmitter } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewChild, Input, EventEmitter, HostListener } from '@angular/core';
import { PostsService } from 'app/posts.services';
import { trigger, transition, animateChild, stagger, query, style, animate } from '@angular/animations';
import { Router } from '@angular/router';
@@ -13,31 +13,7 @@ import { Download } from 'api-types';
@Component({
selector: 'app-downloads',
templateUrl: './downloads.component.html',
styleUrls: ['./downloads.component.scss'],
animations: [
// nice stagger effect when showing existing elements
trigger('list', [
transition(':enter', [
// child animation selector + stagger
query('@items',
stagger(100, animateChild()), { optional: true }
)
]),
]),
trigger('items', [
// cubic-bezier for a tiny bouncing feel
transition(':enter', [
style({ transform: 'scale(0.5)', opacity: 0 }),
animate('500ms cubic-bezier(.8,-0.6,0.2,1.5)',
style({ transform: 'scale(1)', opacity: 1 }))
]),
transition(':leave', [
style({ transform: 'scale(1)', opacity: 1, height: '*' }),
animate('1s cubic-bezier(.8,-0.6,0.2,1.5)',
style({ transform: 'scale(0.5)', opacity: 0, height: '0px', margin: '0px' }))
]),
])
],
styleUrls: ['./downloads.component.scss']
})
export class DownloadsComponent implements OnInit, OnDestroy {
@@ -62,13 +38,76 @@ export class DownloadsComponent implements OnInit, OnDestroy {
3: $localize`Complete`
}
displayedColumns: string[] = ['timestamp_start', 'title', 'step_index', 'sub_name', 'percent_complete', 'actions'];
displayedColumnsBig: string[] = ['timestamp_start', 'title', 'step_index', 'sub_name', 'percent_complete', 'actions'];
displayedColumnsSmall: string[] = ['title', 'step_index', 'percent_complete', 'actions'];
displayedColumns: string[] = this.displayedColumnsBig;
dataSource = null; // new MatTableDataSource<Download>();
// The purpose of this is to reduce code reuse for displaying these actions as icons or in a menu
downloadActions: DownloadAction[] = [
{
tooltip: $localize`Watch content`,
action: (download: Download) => this.watchContent(download),
show: (download: Download) => download.finished && !download.error,
icon: 'smart_display'
},
{
tooltip: $localize`Show error`,
action: (download: Download) => this.showError(download),
show: (download: Download) => download.finished && !!download.error,
icon: 'warning'
},
{
tooltip: $localize`Restart`,
action: (download: Download) => this.restartDownload(download),
show: (download: Download) => download.finished,
icon: 'restart_alt'
},
{
tooltip: $localize`Pause`,
action: (download: Download) => this.pauseDownload(download),
show: (download: Download) => !download.finished && (!download.paused || !download.finished_step),
icon: 'pause'
},
{
tooltip: $localize`Resume`,
action: (download: Download) => this.resumeDownload(download),
show: (download: Download) => !download.finished && download.paused && download.finished_step,
icon: 'play_arrow'
},
{
tooltip: $localize`Resume`,
action: (download: Download) => this.resumeDownload(download),
show: (download: Download) => !download.finished && download.paused && download.finished_step,
icon: 'play_arrow'
},
{
tooltip: $localize`Cancel`,
action: (download: Download) => this.cancelDownload(download),
show: (download: Download) => false && !download.finished && !download.paused, // TODO: add possibility to cancel download
icon: 'cancel'
},
{
tooltip: $localize`Clear`,
action: (download: Download) => this.clearDownload(download),
show: (download: Download) => download.finished || download.paused,
icon: 'delete'
}
]
downloads_retrieved = false;
innerWidth: number;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@HostListener('window:resize', ['$event'])
onResize(): void {
this.innerWidth = window.innerWidth;
this.resizeColumns();
}
sort_downloads = (a: Download, b: Download): number => {
const result = b.timestamp_start - a.timestamp_start;
return result;
@@ -77,6 +116,8 @@ export class DownloadsComponent implements OnInit, OnDestroy {
constructor(public postsService: PostsService, private router: Router, private dialog: MatDialog, private clipboard: Clipboard) { }
ngOnInit(): void {
this.innerWidth = window.innerWidth;
this.resizeColumns();
if (this.postsService.initialized) {
this.getCurrentDownloadsRecurring();
} else {
@@ -164,8 +205,8 @@ export class DownloadsComponent implements OnInit, OnDestroy {
});
}
pauseDownload(download_uid: string): void {
this.postsService.pauseDownload(download_uid).subscribe(res => {
pauseDownload(download: Download): void {
this.postsService.pauseDownload(download['uid']).subscribe(res => {
if (!res['success']) {
this.postsService.openSnackBar($localize`Failed to pause download! See server logs for more info.`);
}
@@ -180,8 +221,8 @@ export class DownloadsComponent implements OnInit, OnDestroy {
});
}
resumeDownload(download_uid: string): void {
this.postsService.resumeDownload(download_uid).subscribe(res => {
resumeDownload(download: Download): void {
this.postsService.resumeDownload(download['uid']).subscribe(res => {
if (!res['success']) {
this.postsService.openSnackBar($localize`Failed to resume download! See server logs for more info.`);
}
@@ -196,8 +237,8 @@ export class DownloadsComponent implements OnInit, OnDestroy {
});
}
restartDownload(download_uid: string): void {
this.postsService.restartDownload(download_uid).subscribe(res => {
restartDownload(download: Download): void {
this.postsService.restartDownload(download['uid']).subscribe(res => {
if (!res['success']) {
this.postsService.openSnackBar($localize`Failed to restart download! See server logs for more info.`);
} else {
@@ -208,16 +249,16 @@ export class DownloadsComponent implements OnInit, OnDestroy {
});
}
cancelDownload(download_uid: string): void {
this.postsService.cancelDownload(download_uid).subscribe(res => {
cancelDownload(download: Download): void {
this.postsService.cancelDownload(download['uid']).subscribe(res => {
if (!res['success']) {
this.postsService.openSnackBar($localize`Failed to cancel download! See server logs for more info.`);
}
});
}
clearDownload(download_uid: string): void {
this.postsService.clearDownload(download_uid).subscribe(res => {
clearDownload(download: Download): void {
this.postsService.clearDownload(download['uid']).subscribe(res => {
if (!res['success']) {
this.postsService.openSnackBar($localize`Failed to pause download! See server logs for more info.`);
}
@@ -257,6 +298,7 @@ export class DownloadsComponent implements OnInit, OnDestroy {
}
showError(download: Download): void {
console.log(download)
const copyToClipboardEmitter = new EventEmitter<boolean>();
this.dialog.open(ConfirmDialogComponent, {
data: {
@@ -276,4 +318,16 @@ export class DownloadsComponent implements OnInit, OnDestroy {
}
});
}
resizeColumns() {
if (this.innerWidth < 650) this.displayedColumns = this.displayedColumnsSmall;
else this.displayedColumns = this.displayedColumnsBig;
}
}
interface DownloadAction {
tooltip: string,
action: (download: Download) => void,
show: (download: Download) => boolean,
icon: string
}

View File

@@ -205,7 +205,7 @@
</div>
<div style="display: flex; justify-content: center;" *ngIf="downloads && downloads.length > 0 && !autoplay">
<app-downloads style="width: 80%; margin-bottom: 10px" [uids]="download_uids"></app-downloads>
<app-downloads style="width: 80%; min-width: 350px; margin-bottom: 10px" [uids]="download_uids"></app-downloads>
</div>
<ng-container *ngIf="cachedFileManagerEnabled || fileManagerEnabled">