diff options
author | Chocobozzz <me@florianbigard.com> | 2019-04-05 10:52:27 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-04-05 10:53:09 +0200 |
commit | 3a0fb65c61f80b510bce979a45d59d17948745e8 (patch) | |
tree | c1be0b2158a008fea826835c8d2fd4e8d648bae9 /client/src/app/shared/video/modals | |
parent | 693263e936763a851e3c8c020e3739def8bd4eca (diff) | |
download | PeerTube-3a0fb65c61f80b510bce979a45d59d17948745e8.tar.gz PeerTube-3a0fb65c61f80b510bce979a45d59d17948745e8.tar.zst PeerTube-3a0fb65c61f80b510bce979a45d59d17948745e8.zip |
Add video miniature dropdown
Diffstat (limited to 'client/src/app/shared/video/modals')
9 files changed, 393 insertions, 0 deletions
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.html b/client/src/app/shared/video/modals/video-blacklist.component.html new file mode 100644 index 000000000..1a87bdcd4 --- /dev/null +++ b/client/src/app/shared/video/modals/video-blacklist.component.html | |||
@@ -0,0 +1,38 @@ | |||
1 | <ng-template #modal> | ||
2 | <div class="modal-header"> | ||
3 | <h4 i18n class="modal-title">Blacklist video</h4> | ||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
5 | </div> | ||
6 | |||
7 | <div class="modal-body"> | ||
8 | |||
9 | <form novalidate [formGroup]="form" (ngSubmit)="blacklist()"> | ||
10 | <div class="form-group"> | ||
11 | <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }"> | ||
12 | </textarea> | ||
13 | <div *ngIf="formErrors.reason" class="form-error"> | ||
14 | {{ formErrors.reason }} | ||
15 | </div> | ||
16 | </div> | ||
17 | |||
18 | <div class="form-group" *ngIf="video.isLocal"> | ||
19 | <my-peertube-checkbox | ||
20 | inputName="unfederate" formControlName="unfederate" | ||
21 | i18n-labelText labelText="Unfederate the video (ask for its deletion from the remote instances)" | ||
22 | ></my-peertube-checkbox> | ||
23 | </div> | ||
24 | |||
25 | <div class="form-group inputs"> | ||
26 | <span i18n class="action-button action-button-cancel" (click)="hide()"> | ||
27 | Cancel | ||
28 | </span> | ||
29 | |||
30 | <input | ||
31 | type="submit" i18n-value value="Submit" class="action-button-submit" | ||
32 | [disabled]="!form.valid" | ||
33 | > | ||
34 | </div> | ||
35 | </form> | ||
36 | |||
37 | </div> | ||
38 | </ng-template> | ||
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.scss b/client/src/app/shared/video/modals/video-blacklist.component.scss new file mode 100644 index 000000000..afcdb9a16 --- /dev/null +++ b/client/src/app/shared/video/modals/video-blacklist.component.scss | |||
@@ -0,0 +1,6 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | textarea { | ||
5 | @include peertube-textarea(100%, 100px); | ||
6 | } | ||
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.ts b/client/src/app/shared/video/modals/video-blacklist.component.ts new file mode 100644 index 000000000..4e4e8dc50 --- /dev/null +++ b/client/src/app/shared/video/modals/video-blacklist.component.ts | |||
@@ -0,0 +1,76 @@ | |||
1 | import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' | ||
2 | import { Notifier, RedirectService } from '@app/core' | ||
3 | import { VideoBlacklistService } from '../../../shared/video-blacklist' | ||
4 | import { VideoDetails } from '../../../shared/video/video-details.model' | ||
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
6 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
7 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
8 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | ||
9 | import { FormReactive, VideoBlacklistValidatorsService } from '@app/shared/forms' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-video-blacklist', | ||
13 | templateUrl: './video-blacklist.component.html', | ||
14 | styleUrls: [ './video-blacklist.component.scss' ] | ||
15 | }) | ||
16 | export class VideoBlacklistComponent extends FormReactive implements OnInit { | ||
17 | @Input() video: VideoDetails = null | ||
18 | |||
19 | @ViewChild('modal') modal: NgbModal | ||
20 | |||
21 | @Output() videoBlacklisted = new EventEmitter() | ||
22 | |||
23 | error: string = null | ||
24 | |||
25 | private openedModal: NgbModalRef | ||
26 | |||
27 | constructor ( | ||
28 | protected formValidatorService: FormValidatorService, | ||
29 | private modalService: NgbModal, | ||
30 | private videoBlacklistValidatorsService: VideoBlacklistValidatorsService, | ||
31 | private videoBlacklistService: VideoBlacklistService, | ||
32 | private notifier: Notifier, | ||
33 | private redirectService: RedirectService, | ||
34 | private i18n: I18n | ||
35 | ) { | ||
36 | super() | ||
37 | } | ||
38 | |||
39 | ngOnInit () { | ||
40 | const defaultValues = { unfederate: 'true' } | ||
41 | |||
42 | this.buildForm({ | ||
43 | reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON, | ||
44 | unfederate: null | ||
45 | }, defaultValues) | ||
46 | } | ||
47 | |||
48 | show () { | ||
49 | this.openedModal = this.modalService.open(this.modal, { keyboard: false }) | ||
50 | } | ||
51 | |||
52 | hide () { | ||
53 | this.openedModal.close() | ||
54 | this.openedModal = null | ||
55 | } | ||
56 | |||
57 | blacklist () { | ||
58 | const reason = this.form.value[ 'reason' ] || undefined | ||
59 | const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined | ||
60 | |||
61 | this.videoBlacklistService.blacklistVideo(this.video.id, reason, unfederate) | ||
62 | .subscribe( | ||
63 | () => { | ||
64 | this.notifier.success(this.i18n('Video blacklisted.')) | ||
65 | this.hide() | ||
66 | |||
67 | this.video.blacklisted = true | ||
68 | this.video.blacklistedReason = reason | ||
69 | |||
70 | this.videoBlacklisted.emit() | ||
71 | }, | ||
72 | |||
73 | err => this.notifier.error(err.message) | ||
74 | ) | ||
75 | } | ||
76 | } | ||
diff --git a/client/src/app/shared/video/modals/video-download.component.html b/client/src/app/shared/video/modals/video-download.component.html new file mode 100644 index 000000000..2bb5d6d37 --- /dev/null +++ b/client/src/app/shared/video/modals/video-download.component.html | |||
@@ -0,0 +1,52 @@ | |||
1 | <ng-template #modal let-hide="close"> | ||
2 | <div class="modal-header"> | ||
3 | <h4 i18n class="modal-title">Download video</h4> | ||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
5 | </div> | ||
6 | |||
7 | <div class="modal-body"> | ||
8 | <div class="form-group"> | ||
9 | <div class="input-group input-group-sm"> | ||
10 | <div class="input-group-prepend peertube-select-container"> | ||
11 | <select [(ngModel)]="resolutionId"> | ||
12 | <option *ngFor="let file of video.files" [value]="file.resolution.id">{{ file.resolution.label }}</option> | ||
13 | </select> | ||
14 | </div> | ||
15 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> | ||
16 | <div class="input-group-append"> | ||
17 | <button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | ||
18 | <span class="glyphicon glyphicon-copy"></span> | ||
19 | </button> | ||
20 | </div> | ||
21 | </div> | ||
22 | </div> | ||
23 | |||
24 | <div class="download-type"> | ||
25 | <div class="peertube-radio-container"> | ||
26 | <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct"> | ||
27 | <label i18n for="download-direct">Direct download</label> | ||
28 | </div> | ||
29 | |||
30 | <div class="peertube-radio-container"> | ||
31 | <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> | ||
32 | <label i18n for="download-torrent">Torrent (.torrent file)</label> | ||
33 | </div> | ||
34 | |||
35 | <div class="peertube-radio-container"> | ||
36 | <input type="radio" name="download" id="download-magnet" [(ngModel)]="downloadType" value="magnet"> | ||
37 | <label i18n for="download-magnet">Torrent (magnet link)</label> | ||
38 | </div> | ||
39 | </div> | ||
40 | </div> | ||
41 | |||
42 | <div class="modal-footer inputs"> | ||
43 | <span i18n class="action-button action-button-cancel" (click)="hide()"> | ||
44 | Cancel | ||
45 | </span> | ||
46 | |||
47 | <input | ||
48 | type="submit" i18n-value value="Download" class="action-button-submit" | ||
49 | (click)="download()" | ||
50 | > | ||
51 | </div> | ||
52 | </ng-template> | ||
diff --git a/client/src/app/shared/video/modals/video-download.component.scss b/client/src/app/shared/video/modals/video-download.component.scss new file mode 100644 index 000000000..3e826c3b6 --- /dev/null +++ b/client/src/app/shared/video/modals/video-download.component.scss | |||
@@ -0,0 +1,25 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | .peertube-select-container { | ||
5 | @include peertube-select-container(100px); | ||
6 | |||
7 | border-top-right-radius: 0; | ||
8 | border-bottom-right-radius: 0; | ||
9 | border-right: none; | ||
10 | |||
11 | select { | ||
12 | height: inherit; | ||
13 | } | ||
14 | } | ||
15 | |||
16 | .download-type { | ||
17 | margin-top: 30px; | ||
18 | |||
19 | .peertube-radio-container { | ||
20 | @include peertube-radio-container; | ||
21 | |||
22 | display: inline-block; | ||
23 | margin-right: 30px; | ||
24 | } | ||
25 | } | ||
diff --git a/client/src/app/shared/video/modals/video-download.component.ts b/client/src/app/shared/video/modals/video-download.component.ts new file mode 100644 index 000000000..64aaeb3c8 --- /dev/null +++ b/client/src/app/shared/video/modals/video-download.component.ts | |||
@@ -0,0 +1,69 @@ | |||
1 | import { Component, ElementRef, ViewChild } from '@angular/core' | ||
2 | import { VideoDetails } from '../../../shared/video/video-details.model' | ||
3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | import { Notifier } from '@app/core' | ||
6 | |||
7 | @Component({ | ||
8 | selector: 'my-video-download', | ||
9 | templateUrl: './video-download.component.html', | ||
10 | styleUrls: [ './video-download.component.scss' ] | ||
11 | }) | ||
12 | export class VideoDownloadComponent { | ||
13 | @ViewChild('modal') modal: ElementRef | ||
14 | |||
15 | downloadType: 'direct' | 'torrent' | 'magnet' = 'torrent' | ||
16 | resolutionId: number | string = -1 | ||
17 | |||
18 | private video: VideoDetails | ||
19 | |||
20 | constructor ( | ||
21 | private notifier: Notifier, | ||
22 | private modalService: NgbModal, | ||
23 | private i18n: I18n | ||
24 | ) { } | ||
25 | |||
26 | show (video: VideoDetails) { | ||
27 | this.video = video | ||
28 | |||
29 | const m = this.modalService.open(this.modal) | ||
30 | m.result.then(() => this.onClose()) | ||
31 | .catch(() => this.onClose()) | ||
32 | |||
33 | this.resolutionId = this.video.files[0].resolution.id | ||
34 | } | ||
35 | |||
36 | onClose () { | ||
37 | this.video = undefined | ||
38 | } | ||
39 | |||
40 | download () { | ||
41 | window.location.assign(this.getLink()) | ||
42 | } | ||
43 | |||
44 | getLink () { | ||
45 | // HTML select send us a string, so convert it to a number | ||
46 | this.resolutionId = parseInt(this.resolutionId.toString(), 10) | ||
47 | |||
48 | const file = this.video.files.find(f => f.resolution.id === this.resolutionId) | ||
49 | if (!file) { | ||
50 | console.error('Could not find file with resolution %d.', this.resolutionId) | ||
51 | return | ||
52 | } | ||
53 | |||
54 | switch (this.downloadType) { | ||
55 | case 'direct': | ||
56 | return file.fileDownloadUrl | ||
57 | |||
58 | case 'torrent': | ||
59 | return file.torrentDownloadUrl | ||
60 | |||
61 | case 'magnet': | ||
62 | return file.magnetUri | ||
63 | } | ||
64 | } | ||
65 | |||
66 | activateCopiedMessage () { | ||
67 | this.notifier.success(this.i18n('Copied')) | ||
68 | } | ||
69 | } | ||
diff --git a/client/src/app/shared/video/modals/video-report.component.html b/client/src/app/shared/video/modals/video-report.component.html new file mode 100644 index 000000000..b9434da26 --- /dev/null +++ b/client/src/app/shared/video/modals/video-report.component.html | |||
@@ -0,0 +1,36 @@ | |||
1 | <ng-template #modal> | ||
2 | <div class="modal-header"> | ||
3 | <h4 i18n class="modal-title">Report video</h4> | ||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
5 | </div> | ||
6 | |||
7 | <div class="modal-body"> | ||
8 | |||
9 | <div i18n class="information"> | ||
10 | Your report will be sent to moderators of {{ currentHost }}. | ||
11 | <ng-container *ngIf="isRemoteVideo()"> It will be forwarded to origin instance {{ originHost }} too.</ng-container> | ||
12 | </div> | ||
13 | |||
14 | <form novalidate [formGroup]="form" (ngSubmit)="report()"> | ||
15 | <div class="form-group"> | ||
16 | <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }"> | ||
17 | </textarea> | ||
18 | <div *ngIf="formErrors.reason" class="form-error"> | ||
19 | {{ formErrors.reason }} | ||
20 | </div> | ||
21 | </div> | ||
22 | |||
23 | <div class="form-group inputs"> | ||
24 | <span i18n class="action-button action-button-cancel" (click)="hide()"> | ||
25 | Cancel | ||
26 | </span> | ||
27 | |||
28 | <input | ||
29 | type="submit" i18n-value value="Submit" class="action-button-submit" | ||
30 | [disabled]="!form.valid" | ||
31 | > | ||
32 | </div> | ||
33 | </form> | ||
34 | |||
35 | </div> | ||
36 | </ng-template> | ||
diff --git a/client/src/app/shared/video/modals/video-report.component.scss b/client/src/app/shared/video/modals/video-report.component.scss new file mode 100644 index 000000000..4713660a2 --- /dev/null +++ b/client/src/app/shared/video/modals/video-report.component.scss | |||
@@ -0,0 +1,10 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | .information { | ||
5 | margin-bottom: 20px; | ||
6 | } | ||
7 | |||
8 | textarea { | ||
9 | @include peertube-textarea(100%, 100px); | ||
10 | } | ||
diff --git a/client/src/app/shared/video/modals/video-report.component.ts b/client/src/app/shared/video/modals/video-report.component.ts new file mode 100644 index 000000000..725dd020f --- /dev/null +++ b/client/src/app/shared/video/modals/video-report.component.ts | |||
@@ -0,0 +1,81 @@ | |||
1 | import { Component, Input, OnInit, ViewChild } from '@angular/core' | ||
2 | import { Notifier } from '@app/core' | ||
3 | import { FormReactive } from '../../../shared/forms' | ||
4 | import { VideoDetails } from '../../../shared/video/video-details.model' | ||
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
6 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
7 | import { VideoAbuseValidatorsService } from '@app/shared/forms/form-validators/video-abuse-validators.service' | ||
8 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
9 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | ||
10 | import { VideoAbuseService } from '@app/shared/video-abuse' | ||
11 | |||
12 | @Component({ | ||
13 | selector: 'my-video-report', | ||
14 | templateUrl: './video-report.component.html', | ||
15 | styleUrls: [ './video-report.component.scss' ] | ||
16 | }) | ||
17 | export class VideoReportComponent extends FormReactive implements OnInit { | ||
18 | @Input() video: VideoDetails = null | ||
19 | |||
20 | @ViewChild('modal') modal: NgbModal | ||
21 | |||
22 | error: string = null | ||
23 | |||
24 | private openedModal: NgbModalRef | ||
25 | |||
26 | constructor ( | ||
27 | protected formValidatorService: FormValidatorService, | ||
28 | private modalService: NgbModal, | ||
29 | private videoAbuseValidatorsService: VideoAbuseValidatorsService, | ||
30 | private videoAbuseService: VideoAbuseService, | ||
31 | private notifier: Notifier, | ||
32 | private i18n: I18n | ||
33 | ) { | ||
34 | super() | ||
35 | } | ||
36 | |||
37 | get currentHost () { | ||
38 | return window.location.host | ||
39 | } | ||
40 | |||
41 | get originHost () { | ||
42 | if (this.isRemoteVideo()) { | ||
43 | return this.video.account.host | ||
44 | } | ||
45 | |||
46 | return '' | ||
47 | } | ||
48 | |||
49 | ngOnInit () { | ||
50 | this.buildForm({ | ||
51 | reason: this.videoAbuseValidatorsService.VIDEO_ABUSE_REASON | ||
52 | }) | ||
53 | } | ||
54 | |||
55 | show () { | ||
56 | this.openedModal = this.modalService.open(this.modal, { keyboard: false }) | ||
57 | } | ||
58 | |||
59 | hide () { | ||
60 | this.openedModal.close() | ||
61 | this.openedModal = null | ||
62 | } | ||
63 | |||
64 | report () { | ||
65 | const reason = this.form.value['reason'] | ||
66 | |||
67 | this.videoAbuseService.reportVideo(this.video.id, reason) | ||
68 | .subscribe( | ||
69 | () => { | ||
70 | this.notifier.success(this.i18n('Video reported.')) | ||
71 | this.hide() | ||
72 | }, | ||
73 | |||
74 | err => this.notifier.error(err.message) | ||
75 | ) | ||
76 | } | ||
77 | |||
78 | isRemoteVideo () { | ||
79 | return !this.video.isLocal | ||
80 | } | ||
81 | } | ||