diff --git a/package.json b/package.json index d3ee4a45..4445e270 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "ng": "ng", "start": "ng serve", "dev": "ng build --watch --output-path=\"dev/www/private\"", + "dev-login": "ng build --watch --project=login --output-path=\"dev/www/public\"", "build": "ng build", "build_prod": "ng build --prod", "test": "ng test", diff --git a/projects/login/src/app/login-page/login-page.component.html b/projects/login/src/app/login-page/login-page.component.html index 0f3831f6..231e59af 100644 --- a/projects/login/src/app/login-page/login-page.component.html +++ b/projects/login/src/app/login-page/login-page.component.html @@ -5,10 +5,10 @@ - +
-

qBittorrent Web UI

+

qBittorrent

Sign in below to continue.
diff --git a/projects/login/src/app/login-page/login-page.component.scss b/projects/login/src/app/login-page/login-page.component.scss index 273562f0..a4a9fd38 100644 --- a/projects/login/src/app/login-page/login-page.component.scss +++ b/projects/login/src/app/login-page/login-page.component.scss @@ -37,9 +37,12 @@ width: 60%; - /*Animations short-hand: {duration} {timing-function} {dekay} {itetarion-count} {nameOfAnimation}*/ + /*Animations short-hand: {duration} {timing-function} {delay} {itetarion-count} {nameOfAnimation}*/ animation: 0.4s ease-out 0s 1 slideInAndFadeFromBottom; + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + border-radius: 7px; + mat-card-content { height: 100%; @@ -78,10 +81,16 @@ } } +.dark-theme { + mat-card { + box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 24px; + } +} + /*Rise up tranistion*/ @keyframes slideInAndFadeFromBottom{ 0% { - transform: translateY(20%); + transform: translateY(10%); opacity: 0; } diff --git a/src/app/app.config.json b/src/app/app.config.json index 018752be..6ba6f3d9 100644 --- a/src/app/app.config.json +++ b/src/app/app.config.json @@ -1,3 +1,3 @@ { - "version": "1.15.1" + "version": "1.16.0" } diff --git a/src/app/file-system-tree-explorer/file-system-tree-explorer.component.ts b/src/app/file-system-tree-explorer/file-system-tree-explorer.component.ts index d19ca1be..7ac8250b 100644 --- a/src/app/file-system-tree-explorer/file-system-tree-explorer.component.ts +++ b/src/app/file-system-tree-explorer/file-system-tree-explorer.component.ts @@ -45,8 +45,6 @@ export class FileSystemTreeExplorerComponent implements OnChanges { ngOnInit(): void { this._updateData(); - - console.log('allow set priority?', this.allowSetPriority) } ngOnChanges(changes: SimpleChanges) { diff --git a/src/app/global-transfer-info/global-transfer-info.component.html b/src/app/global-transfer-info/global-transfer-info.component.html index 4d5b22e6..76d7cb78 100644 --- a/src/app/global-transfer-info/global-transfer-info.component.html +++ b/src/app/global-transfer-info/global-transfer-info.component.html @@ -1,16 +1,34 @@
+
+

qBittorrent

+
+ + + +
+
+
+ speed +

Toggle alt limit

+
+ + + +
+
+
- + refresh

Refresh Interval: {{refreshInterval / 1000}}s

- + storage

Free space: {{getFreeSpaceOnDisk()}}

@@ -18,16 +36,14 @@

Free space: {{getFreeSpaceOnDisk()}}

-
- -
+
- - arrow_downward + + arrow_downward

{{getDownloadSpeedString()}} {{getDownLimitString()}}

@@ -37,8 +53,8 @@

Downloaded: {{getDownloadedString()}}


- - arrow_upward + + arrow_upward

{{getUploadSpeedString()}} {{getUpLimitString()}}

@@ -50,18 +66,65 @@

Uploaded: {{getUploadedString()}}

-
-
- -
-
+ -
-
- - speed - -
+
+

+ Filter Status +

+ + + + +

All

+
+ + + + arrow_downward +

Downloading

+
+ + + arrow_upward +

Seeding

+
+ + + done +

Completed

+
+ + + play_arrow +

Resumed

+
+ + + pause +

Paused

+
+ + + toggle_on +

Active

+
+ + + toggle_off +

Inactive

+
+ + + refresh +

Stalled

+
+ + + error +

Errored

+
+
diff --git a/src/app/global-transfer-info/global-transfer-info.component.scss b/src/app/global-transfer-info/global-transfer-info.component.scss index 7043be2a..0446c293 100644 --- a/src/app/global-transfer-info/global-transfer-info.component.scss +++ b/src/app/global-transfer-info/global-transfer-info.component.scss @@ -1,37 +1,60 @@ .global-transfer-info-container { - height: 100%; + height: 100vh; + width: 220px; .data-container { - height: 100%; + height: 100vh; + overflow-y: auto; display: flex; flex-direction: column; - box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.05), 0 3px 10px 0 rgba(0, 0, 0, 0.1); + border-radius: 0; + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; - section h2 { - font-weight: 400; + padding: 0; + + mat-divider.spaced { + margin: 5px 0; } - #disk_summary, #global_transfer { - display: flex; - flex-direction: column; + #qbittorrent_name { + background: #1976D2; + color: white; - width: 100%; + height: 64px; + margin-bottom: 0; } - #global_transfer { - flex-grow: 1; + #toggle_alt_limit { + h4 { + margin: 0 0 0 5px; + font-size: 10pt; + } } - #bottom_actions { - width: 100%; + section { + padding: 10px; - #useAltLimits > label > span { - display: flex; - align-items: center; + h2 { + font-weight: 400; } } + + #disk_summary, #global_transfer { + display: flex; + flex-direction: column; + + width: 100%; + } + } +} + +.dark-theme { + .data-container { + #qbittorrent_name { + background: #212121; + } } } @@ -47,24 +70,70 @@ h3 { margin: 0; } -#summaryContent h4 { +h4 { font-size: 10pt; margin: 0 5px 0 5px; } mat-chip { - border-radius: 0; + border-radius: 10px; width: 100%; - cursor: pointer; } -/** For small screens */ -@media only screen and (max-width: 1550px) { - .global-transfer-info-container { - padding-top: 0; +#summaryContent { + mat-chip { + background: rgba(0, 0, 0, 0.08); + + h4 { + font-size: 10pt; + margin: 0 0 0 5px; + } + } +} + +#filter_torrents { + h3 { + font-size: 11pt; + margin-bottom: 0; + } + + mat-chip { + color: black; + + border-radius: 0; + cursor: pointer; + + background: none; + + border: solid 2px; + border-color:rgba(0, 0, 0, 0.07); + + h4 { + font-size: 10pt; + margin: 0 0 0 5px; + } + + &.mat-chip-selected { + background: rgb(224, 224, 224); + } + } +} + +.dark-theme { + #summaryContent { + mat-chip { + background: rgba(97, 97, 97, 0.5); + } + } - .hide-small { - display: none; + #filter_torrents { + mat-chip { + color: white; + border-color: rgba(97, 97, 97, 0.5); + + &.mat-chip-selected { + background: rgb(97, 97, 97); + } } } } diff --git a/src/app/global-transfer-info/global-transfer-info.component.ts b/src/app/global-transfer-info/global-transfer-info.component.ts index ce848e46..76b099df 100644 --- a/src/app/global-transfer-info/global-transfer-info.component.ts +++ b/src/app/global-transfer-info/global-transfer-info.component.ts @@ -7,6 +7,8 @@ import { ThemeService } from 'src/app/services/theme.service'; import { Observable } from 'rxjs'; import { NetworkConnectionInformationService } from 'src/app/services/network/network-connection-information.service'; import { RateLimitsDialogComponent } from '../modals/rate-limits-dialog/rate-limits-dialog.component'; +import { IsMobileUser } from 'src/utils/Helpers'; +import { TorrentFilterService } from '../services/torrent-filter-service.service'; @Component({ selector: 'app-global-transfer-info', @@ -16,16 +18,17 @@ import { RateLimitsDialogComponent } from '../modals/rate-limits-dialog/rate-lim export class GlobalTransferInfoComponent implements OnInit { public data: GlobalTransferInfo = null; - public isAltSpeedEnabled: boolean; + public isAltSpeedEnabled: boolean; public refreshInterval = -1; - public isDarkTheme: Observable; + public filteringBy = 'all'; - private rateLimitDiaglogRef: MatDialogRef; + public isDarkTheme: Observable; + public isMobileUser = IsMobileUser(); constructor(private data_store: TorrentDataStoreService, private networkInfo: NetworkConnectionInformationService, private units_helper: - UnitsHelperService, private rateLimitDialog: MatDialog, private theme: ThemeService) { } + UnitsHelperService, private rateLimitDialog: MatDialog, private filterService: TorrentFilterService, private theme: ThemeService) { } ngOnInit(): void { this.isDarkTheme = this.theme.getThemeSubscription(); @@ -50,7 +53,7 @@ export class GlobalTransferInfoComponent implements OnInit { } handleDownloadLimitSelect() { - this.rateLimitDiaglogRef = this.rateLimitDialog.open(RateLimitsDialogComponent, { + this.rateLimitDialog.open(RateLimitsDialogComponent, { autoFocus: false, data: { for: 'Download', @@ -61,7 +64,7 @@ export class GlobalTransferInfoComponent implements OnInit { } handleUploadLimitSelect() { - this.rateLimitDiaglogRef = this.rateLimitDialog.open(RateLimitsDialogComponent, { + this.rateLimitDialog.open(RateLimitsDialogComponent, { autoFocus: false, data: { for: 'Upload', @@ -71,6 +74,13 @@ export class GlobalTransferInfoComponent implements OnInit { }); } + handleFilterStatusSelect(filterChosen: any) { + this.filteringBy = filterChosen; + this.filterService.updateFilter(filterChosen); + } + + isSelected(chip: string) { return this.filteringBy === chip } + async toggleAltSpeedLimits() { console.log('toggled alt limits') this.isAltSpeedEnabled = !this.isAltSpeedEnabled diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 5d43129c..237acf08 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,72 +1,72 @@
+
+ - -
- -
-

qBittorrent

-
- - - -
- - - - - -
- -
-
- - - - - - - - - - - +
+ +
+
+ + + + + + + -
+ + + + + + +
+
+
- -
- -
- - + +
+ +
+
diff --git a/src/app/home/home.component.css b/src/app/home/home.component.scss similarity index 50% rename from src/app/home/home.component.css rename to src/app/home/home.component.scss index e3d8ba7a..2bcfa93b 100644 --- a/src/app/home/home.component.css +++ b/src/app/home/home.component.scss @@ -1,39 +1,54 @@ +@import "../../variables.scss"; + +.toolbar { + padding: 0 15px; + width: 100%; +} + +mat-toolbar { + padding: 0; +} + .mat-toolbar { - background: #1976D2; color: white; - padding: 0 25px; + margin: 15px 0 5px 0; - margin-bottom: 15px; + padding-right: 25px; display: flex; flex-direction: row; justify-content: space-between; align-items: center; -} -.dark-theme .mat-toolbar { - background: #212121; -} + background: transparent; + border-radius: 5px; + -.mat-toolbar h1 { - font-size: 22pt; -} + #app-search-torrents { + flex-grow: 1; + margin: 0; + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + } + h1 { + font-size: 22pt; + } -.mat-toolbar #toolbar_actions{ - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; -} + #toolbar_actions{ + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; -.mat-toolbar #toolbar_actions button{ - margin-left: 25px; -} + button{ + margin-left: 15px; + } -.mat-toolbar #toolbar_actions #slideToggleTheme { - padding-left: 30px; + #slideToggleTheme { + margin-left: 5px; + } + } } .actions { @@ -49,12 +64,8 @@ display: none; } -#addTorrentButton, #logoutButton { +#logoutButton { margin-right: 5px; - font-size: 12pt; - - height: 42px; - width: 130px; } app-search-torrents { @@ -63,6 +74,8 @@ app-search-torrents { flex-grow: 0.6; transition: all ease-in-out 0.4s; + + border-radius: 7px; } app-search-torrents:focus-within { @@ -80,41 +93,42 @@ app-search-torrents:focus-within { } .content { - display: flex; - min-height: 100%; - width: 100%; - - flex-direction: row; - justify-content: space-evenly; + margin: 0 15px; + background: $bg-surface-light-0; + border-radius: 7px; - padding-left: 2px; - padding-right: 2px; + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; } -.content app-torrents-table { - width: 83%; -} +.dark-theme { + .content { + background: $bg-surface-dark-0; + box-shadow: none; + } -.content app-global-transfer-info { - width: 15%; - margin-top: 30px; + .mat-toolbar { + background: inherit; + box-shadow: none; + } } /** For small screens */ -@media only screen and (max-width: 1550px) { +/* @media only screen and (max-width: 1550px) { .content { flex-direction: column; padding: 0 5%; } +} */ - .content app-torrents-table { - width: 100%; - } +.homeContainerMobile { + display: block; - .content app-global-transfer-info { - width: 100%; - margin-top: 10px; + .content { + box-shadow: none; + background: inherit; } + + .mat-toolbar { margin-top: 0; background: inherit; } } /** For phone screens */ diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 65ed6c2a..fbb58191 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -21,7 +21,7 @@ import { IsMobileUser } from 'src/utils/Helpers'; @Component({ selector: 'app-home', templateUrl: './home.component.html', - styleUrls: ['./home.component.css'] + styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit { diff --git a/src/app/home/search-torrents/search-torrents.component.css b/src/app/home/search-torrents/search-torrents.component.css index a185a444..6f6befb6 100644 --- a/src/app/home/search-torrents/search-torrents.component.css +++ b/src/app/home/search-torrents/search-torrents.component.css @@ -10,15 +10,16 @@ width: 100%; } -.searchTorrentsInput { +#torrentSearchInput { + height: 100%; font-size: 12pt; - letter-spacing: 0.06em; + letter-spacing: 0.02rem; border: 0px solid; outline: none; padding-bottom: 7px; - margin: 5px 5px 0 10px; + margin: 5px 0 0 10px; flex-grow: 1; diff --git a/src/app/home/search-torrents/search-torrents.component.html b/src/app/home/search-torrents/search-torrents.component.html index 8215d3f8..f454874a 100644 --- a/src/app/home/search-torrents/search-torrents.component.html +++ b/src/app/home/search-torrents/search-torrents.component.html @@ -1,6 +1,6 @@ - + search - + {{option}} diff --git a/src/app/modals/file-system-dialog/file-system-dialog.component.html b/src/app/modals/file-system-dialog/file-system-dialog.component.html index 7f830764..068b2cc9 100644 --- a/src/app/modals/file-system-dialog/file-system-dialog.component.html +++ b/src/app/modals/file-system-dialog/file-system-dialog.component.html @@ -21,37 +21,37 @@

Choose Save Location


-
-
- -

Location: {{getFilePath() === "" ? "N/A" : getFilePath()}}

-
+
+ -
+
+ Location: {{getFilePath() === "" ? "N/A" : getFilePath()}} +
-
-
- - - - folder - folder_open -
{{dir.value}}
-
{{getNumChildrenString(dir)}}
- -
-
+ +
+ + folder + folder_open +
{{dir.value}}
+
@@ -77,19 +77,22 @@

Location: {{getFilePath() === "" ? "N/A" : getFilePath()}} - - - folder -
{{dir.value}}
-
{{getNumChildrenString(dir)}}
-
-
+ +
+ folder +
{{dir.value}}
+


+ +
+ Location: {{getFilePath() === "" ? "N/A" : getFilePath()}} +
+ diff --git a/src/app/modals/file-system-dialog/file-system-dialog.component.scss b/src/app/modals/file-system-dialog/file-system-dialog.component.scss index dfd9394f..46db6e52 100644 --- a/src/app/modals/file-system-dialog/file-system-dialog.component.scss +++ b/src/app/modals/file-system-dialog/file-system-dialog.component.scss @@ -1,3 +1,6 @@ +@import "~@angular/material/theming"; +@import "../../../variables.scss"; + /** Declare Variables */ $border-dark: #494949; @@ -9,14 +12,68 @@ $border-dark: #494949; padding: 10px; } +.leftNavigation { + padding-left: 0; + padding-right: 3px; + + width: 250px; + height: 450px; + + overflow: auto; +} + +.directoryContents { + height: 450px; + width: 75%; + + overflow-y: scroll; + + .create-new-folder-input { + min-width: 80%; + height: 50px; + + padding: 10px; + padding-left: 20px; + } +} + .file-systme-explorer-container { - min-height: 50vh; - min-width: 70vw; + min-height: 50vh; + min-width: 40vw; - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; + + overflow: hidden; + + .folder { + height: 40px; + width: 100%; + + margin: 5px 5px 5px 0; + padding: 8px 0 3px 0; + + border-radius: 5px; + + cursor: pointer; + overflow-x: scroll; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } - overflow: hidden; + &.selected-folder { + border-right: solid 5px mat-color($my-app-primary); + } + + .folder-icon { + margin: 0 5px 0 10px; + } + + .folder-name { + margin: 0 5px; + } + } } .file-explorer-header { @@ -51,59 +108,41 @@ $border-dark: #494949; } } -.file-explorer-actions { - display: flex; - flex-direction: row; - align-items: center; - - margin-bottom: 10px; - - .left-actions { - display: flex; - flex-direction: row; - align-items: baseline; - - flex-grow: 1; - max-width: 90%; - - #saveLocation { - margin: 0; - margin-left: 20px; - max-width: 90%; - word-wrap: break-word; - } - } +#fs-navigator { + width: 100%; + margin-bottom: 25px; } -.leftNavigation { - padding-left: 0; - padding-right: 0; - flex-grow: 1; - - max-width: 300px; - height: 450px; - - overflow-y: scroll; -} +#saveLocation { + flex-grow: 1; + margin: 0 15px; + padding: 0 15px; -.directoryContents { - flex-grow: 4; + height: 36px; - height: 450px; + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + border-radius: 5px; - overflow-y: scroll; + overflow: auto; - max-width: 75%; + // Hacky, need to center the text + // span { margin-top: 6px; } +} - .create-new-folder-input { - min-width: 80%; - height: 50px; +.dark-theme { + .file-systme-explorer-container { + .folder { + &:hover { + background: rgba(255, 255, 255, 0.1); + } - padding: 10px; - padding-left: 20px; + &.selected-folder { + border-right: solid 5px mat-color($dark-accent); + } } -} + } -#isFolderSelected { - justify-self: flex-end; + #saveLocation { + background: $table-surface-1; + } } diff --git a/src/app/services/torrent-filter-service.service.ts b/src/app/services/torrent-filter-service.service.ts new file mode 100644 index 00000000..7720da4e --- /dev/null +++ b/src/app/services/torrent-filter-service.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class TorrentFilterService { + private _filterSource = new BehaviorSubject(""); + private _filterValue = this._filterSource.asObservable(); + + constructor() { } + + public updateFilter(newVal: string): void { + this._filterSource.next(newVal); + } + + /** Get filter value as it's updated */ + public getFilterValue(): Observable { + return this._filterValue; + } +} diff --git a/src/app/torrents-table/bulk-update-torrents/bulk-update-torrents.component.scss b/src/app/torrents-table/bulk-update-torrents/bulk-update-torrents.component.scss index 3dc3f033..4b2b7b15 100644 --- a/src/app/torrents-table/bulk-update-torrents/bulk-update-torrents.component.scss +++ b/src/app/torrents-table/bulk-update-torrents/bulk-update-torrents.component.scss @@ -1,14 +1,17 @@ $border-dark: #6F6F6F; #bulk-update-card { - padding: 0 20px 0 30px; - margin-top: 30px; + padding: 0 20px 0 15px; display: flex; flex-direction: row; align-items: baseline; border-radius: 0; + + // Same as in home.component.scss + border-top-left-radius: 10px; + border-top-right-radius: 10px; } .spacer { @@ -38,10 +41,3 @@ $border-dark: #6F6F6F; .mat-card-info button { margin-left: 20px; } - -.refresh-interval { - mat-chip { - letter-spacing: 0.05em; - border-radius: 0; - } -} diff --git a/src/app/torrents-table/torrents-table.component.html b/src/app/torrents-table/torrents-table.component.html index 0d6649a4..fbb83d80 100644 --- a/src/app/torrents-table/torrents-table.component.html +++ b/src/app/torrents-table/torrents-table.component.html @@ -10,7 +10,7 @@ - + [indeterminate]="selection.hasValue() && !isAllSelected()" [style]="{marginLeft: '10px'}"> @@ -82,13 +82,13 @@ (contextmenu)="handleTorrentSelected(torrent)" [pContextMenuRow]="torrent" - > + >
+ [checked]="selection.isSelected(torrent)" [style]="{marginLeft: '10px'}">
@@ -175,7 +175,7 @@
-
{{torrent[displayedColumnsMapping[col]]}}
+
{{torrent[displayedColumnsMapping[col]]}}
@@ -241,8 +241,9 @@ -
-

No torrents found. Try adding one by clicking Upload at the top-right.

+
+

No torrents found.

+

Try changing the search value, applying a different filter status, or uploading a torrent.

diff --git a/src/app/torrents-table/torrents-table.component.scss b/src/app/torrents-table/torrents-table.component.scss index 7684e4e5..75a67310 100644 --- a/src/app/torrents-table/torrents-table.component.scss +++ b/src/app/torrents-table/torrents-table.component.scss @@ -18,6 +18,10 @@ overflow: scroll; } +.p-virtualscroller-item { + background: $bg-color-light; +} + .dark-theme { .torrent-card-view { border-color: $dark-default; @@ -103,48 +107,13 @@ mat-spinner { /** Sizes of each column */ .table-col { - width: max-content; - - &.table-col-Name { - overflow-wrap: break-word; - - word-wrap: break-word; - word-break: break-word; - - // width: 450px; - } - - &.table-col-select { width: 50px; } - // &.table-col-Actions { width: 140px; } - // &.table-col-Size { width: 85px; } - // &.table-col-Progress { width: 175px; } - // &.table-col-Status { width: 140px; } - - // &.table-col-Up-Speed { width: 100px; } - // &.table-col-Down-Speed { width: 120px; } - - // &.table-col-ETA { width: 115px; } - // &.table-col-Ratio { width: 75px; } - - // &.table-col-Downloaded { width: 100px; } - // &.table-col-Uploaded { width: 100px; } - - // &.table-col-Added-On { width: 170px; } - // &.table-col-Completed-On { width: 170px; } - // &.table-col-Last-Activity { width: 170px; } - - // &.table-col-Category { width: 120px; } - - // &.table-col-Seeders { width: 85px; } - // &.table-col-Leechers { width: 85px; } + &.table-col-select { width: 40px; } } i.pi { font-size: 15px; } -/** Torrent table header and row styles **/ - .p-datatable .p-datatable-thead > tr > th { background: white; color: rgba(0,0,0,.54); @@ -214,4 +183,4 @@ i.pi { .p-datatable-scrollable-header-box { background: $table-surface-2; } -} +} \ No newline at end of file diff --git a/src/app/torrents-table/torrents-table.component.ts b/src/app/torrents-table/torrents-table.component.ts index af8ac597..986fb1ab 100644 --- a/src/app/torrents-table/torrents-table.component.ts +++ b/src/app/torrents-table/torrents-table.component.ts @@ -24,6 +24,7 @@ import { SnackbarService } from '../services/notifications/snackbar.service'; import { MenuItem } from 'primeng/api'; import { getClassForStatus } from '../../utils/Helpers' import { Constants } from 'src/constants'; +import { TorrentFilterService } from '../services/torrent-filter-service.service'; @Component({ @@ -60,12 +61,14 @@ export class TorrentsTableComponent implements OnInit { private deleteTorDialogRef: MatDialogRef; private infoTorDialogRef: MatDialogRef; private currentMatSort = {active: "Completed On", direction: "desc"}; + private torrentSearchValue = ""; // Keep track of which torrents are currently selected + private torrentFilterValue = ""; constructor(private appConfig: ApplicationConfigService, private data_store: TorrentDataStoreService, private pp: PrettyPrintTorrentDataService, public deleteTorrentDialog: MatDialog, private infoTorDialog: MatDialog, private moveTorrentDialog: MatDialog, - private torrentSearchService: TorrentSearchServiceService, private torrentsSelectedService: RowSelectionService, private snackbar: SnackbarService, - private theme: ThemeService) { } + private torrentSearchService: TorrentSearchServiceService, private filterService: TorrentFilterService, private torrentsSelectedService: RowSelectionService, + private snackbar: SnackbarService, private theme: ThemeService) { } ngOnInit(): void { // Theming @@ -76,6 +79,11 @@ export class TorrentsTableComponent implements OnInit { this.updateTorrentSearchValue(res); }); + // Filtering torrents + this.filterService.getFilterValue().subscribe((res: string) => { + this.updateFilterValue(res); + }) + // Get user preferences this.appConfig.getUserPreferencesSubscription().subscribe(res => { this.setUserPreferences(res) }); @@ -107,7 +115,7 @@ export class TorrentsTableComponent implements OnInit { { label: 'Decrease Priority', icon: 'pi pi-fw pi-chevron-down', command: () => this.decreasePriorityBulk(this.selection.selected) }, { label: 'Max Priority', icon: 'pi pi-fw pi-angle-double-up', command: () => this.maximumPriorityBulk(this.selection.selected) }, { label: 'Min Priority', icon: 'pi pi-fw pi-angle-double-down', command: () => this.minimumPriorityBulk(this.selection.selected) }, - ] + ]; } ngOnDestroy(): void { } @@ -158,6 +166,7 @@ export class TorrentsTableComponent implements OnInit { // Filter by any search criteria this.updateTorrentsBasedOnSearchValue(); + this.updateTorrentsBasedOnFilterValue(); } private updateTorrentSearchValue(val: string): void { @@ -168,6 +177,13 @@ export class TorrentsTableComponent implements OnInit { this.updateTorrentsBasedOnSearchValue() } + private updateFilterValue(val: string) { + val = val ?? ''; + this.torrentFilterValue = val; + + this.updateTorrentsBasedOnFilterValue(); + } + /** Callback for when user is searching for a torrent. Filter all torrents displayed that match torrent criteria * * NOTE: If search value in state is empty, no filtering is done @@ -186,6 +202,21 @@ export class TorrentsTableComponent implements OnInit { } } + updateTorrentsBasedOnFilterValue() { + // If a filter value is given, then do the work + if(this.allTorrentData && this.torrentFilterValue) { + // Sometimes filtered data is empty while not searching, likely a timing issue + // Super hacky... + this.filteredTorrentData = (this.filteredTorrentData.length === 0 && this.torrentSearchValue === '' ? this.allTorrentData : this.filteredTorrentData) + .filter((tor: Torrent) => { + // Special case for when we consider all torrents + if(this.torrentFilterValue === 'All') return true; + + return Constants.TORRENT_STATE_MAPPING[this.torrentFilterValue]?.includes(tor.state); + }); + } + } + handleSortChange(event: any) { if(!this.filteredTorrentData) { return; } @@ -265,6 +296,10 @@ export class TorrentsTableComponent implements OnInit { handleColumnResize(event: any) { let colName = event.element.id.replace(/-/g, ' '); this.appConfig.setColumnWidth(colName, event.delta); + + // Immediately update preferences in-memory + this.colWidths = this.appConfig.getWebUISettings().torrent_table.column_widths; + this.updateTorrentData(this.allTorrentInformation); } /** Determine whether a torrent is selected or not */ diff --git a/src/constants.ts b/src/constants.ts index f1b73665..72f12e44 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,7 +36,7 @@ export class Constants { * Map column name to width in pixels; */ static TORRENT_TABLE_COLUMNS_WIDTHS = { - 'Actions': 140, + 'Actions': 120, 'Name': 450, 'Size': 85, @@ -61,4 +61,22 @@ export class Constants { 'Seeders': 85, 'Leechers': 85 } + + /** + * Map a filter state as defined in global-transfer-info-component + * to a list of states that encompass it. + * + * For example, the state "Error" may apply to any of: `['error', 'stalledDL', 'unknown', etc...]` + */ + static TORRENT_STATE_MAPPING = { + 'Downloading': ['downloading', 'pausedUP'], + 'Seeding': ['uploading', 'stalledUP', 'forcedUP'], + 'Completed': ['uploading', 'stalledUP', 'forcedUP'], + 'Resumed': ['uploading', 'stalledUP', 'forcedUP'], + 'Paused': ['pausedUP', 'pausedDL'], + 'Active': ['uploading', 'downloading', 'allocating', 'metaDL', 'checkingDL', 'moving', 'uploading', 'stalledUP', 'forcedUP'], + 'Inactive': ['pausedUP', 'pausedDL', 'queuedUP', 'queuedDL', 'stalledUP'], + 'Stalled': ['stalledUP', 'stalledDL'], + 'Errored': ['error', 'missingFiles', 'unknown', 'stalledDL'], + } } diff --git a/src/index.html b/src/index.html index 0d4057f3..e349ecac 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,7 @@ - QbitWebUI + qBittorrent diff --git a/src/main.ts b/src/main.ts index 47e65253..c7b673cf 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,7 +6,6 @@ import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); - // window.console.log = function() {} // Disable all console logs in prod } platformBrowserDynamic().bootstrapModule(AppModule) diff --git a/src/styles.scss b/src/styles.scss index a128d02f..d4ec9270 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -8,7 +8,6 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - } .spacer { @@ -27,7 +26,7 @@ body { .space-between { justify-content: space-between; } .space-evenly { justify-content: space-evenly; } .space-around { justify-content: space-around; } - + .wrap { flex-wrap: wrap; } .no-wrap { flex-wrap: nowrap; } @@ -42,16 +41,24 @@ body { .grow-6 { flex-grow: 0.6; } .grow-7 { flex-grow: 0.7; } + +.text-center { text-align: center; } .word-break-all { word-break: break-all; } /** Styles applicable for all material dialogs */ .generic-dialog .mat-dialog-container { padding: 0; overflow: unset; + + border-radius: 15px; } .mat-dialog-inner-container { padding: 24px; + + // Must be less than or equal to border-radius in .mat-dialog-container + border-radius: 10px; + background: white; } .indented_field { @@ -202,8 +209,8 @@ body { /*** CUSTOM SCROLLBAR ***/ ::-webkit-scrollbar { - width: 8px; /** Target vertical scroll-bars */ - height: 8px; /** Target horizontal scroll-bars */ + width: 5px; /** Target vertical scroll-bars */ + height: 5px; /** Target horizontal scroll-bars */ } /* Corner of the track (will sometimes show a small white square) */ @@ -214,10 +221,20 @@ body { /* Handle */ ::-webkit-scrollbar-thumb { background: rgb(131, 131, 131); - border-radius: 10px; } /* Handle on hover */ ::-webkit-scrollbar-thumb:hover { background: #555; } + +.show-mobile { display: none; } +.show-mobile-flex { display: none; } + +/** For phone screens */ +@media only screen and (max-width: 640px) { + .hide-mobile { display: none; } + + .show-mobile { display: block; } + .show-mobile-flex { display: flex; } +} diff --git a/src/theme.scss b/src/theme.scss index 5602dfce..6d11c786 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -2,14 +2,11 @@ @import 'variables.scss'; @include mat-core(); -/** Set primary, secondary and warn colour */ -$background-color: white; - $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn); // Insert custom background color $background: map-get($my-app-theme, background); -$background: map_merge($background, (background: $background-color)); +$background: map_merge($background, (background: $bg-color-light)); $my-app-theme: map_merge($my-app-theme, (background: $background)); @include angular-material-theme($my-app-theme); diff --git a/src/variables.scss b/src/variables.scss index c98e8075..75e59691 100644 --- a/src/variables.scss +++ b/src/variables.scss @@ -1,24 +1,30 @@ @import '~@angular/material/theming'; @include mat-core(); +$bg-color-light: #FAFAFA; + /** Light theme **/ $my-app-default: #e0e0e0; $my-app-primary: mat-palette($mat-blue); $my-app-accent: mat-palette($mat-deep-orange); $my-app-warn: mat-palette($mat-red, 500, 900, A400); +$bg-surface-light-0: white; + /** Dark theme **/ $dark-default: #616161; $dark-primary: mat-palette($mat-blue-gray, 300, 100, 500); $dark-accent: mat-palette($mat-green, 300, 100, 500); $dark-warn: mat-palette($mat-red); +$bg-surface-dark-0: #424242; + /** Torrent table specific */ $table-surface-1: #595959; $table-surface-2: #424242; $table-black-color: rgba(0,0,0,.87); -$bg-surface-0: #383434; +$bg-surface-0: #303030; $row-hover-light: #f2f2f2; $row-hover-dark: #5c5c5c;