diff options
author | Chocobozzz <me@florianbigard.com> | 2019-12-05 10:05:00 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-12-05 10:05:00 +0100 |
commit | 3a1fed11c52705002cbf2a17294509fb5a89237c (patch) | |
tree | 9140310efbd9ba7f1b7254e3fd580e84322792a7 /client/src/app/videos | |
parent | 689a4f6946e47ddf4871fd43bbd1284a4dc79e68 (diff) | |
download | PeerTube-3a1fed11c52705002cbf2a17294509fb5a89237c.tar.gz PeerTube-3a1fed11c52705002cbf2a17294509fb5a89237c.tar.zst PeerTube-3a1fed11c52705002cbf2a17294509fb5a89237c.zip |
Support playlists in share modal
Diffstat (limited to 'client/src/app/videos')
4 files changed, 166 insertions, 141 deletions
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.html b/client/src/app/videos/+video-watch/modal/video-share.component.html index e0be9f265..549a9f30e 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.html +++ b/client/src/app/videos/+video-watch/modal/video-share.component.html | |||
@@ -4,167 +4,176 @@ | |||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | |||
7 | <div class="modal-body"> | 8 | <div class="modal-body"> |
8 | <ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)"> | 9 | <div class="playlist" *ngIf="hasPlaylist()"> |
9 | 10 | <div class="title-page title-page-single" i18n>Share the playlist</div> | |
10 | <ngb-tab i18n-title title="URL" id="url"> | ||
11 | <ng-template ngbTabContent> | ||
12 | |||
13 | <div class="tab-content"> | ||
14 | <div class="input-group"> | ||
15 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoUrl()" /> | ||
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 | 11 | ||
24 | </ng-template> | 12 | <my-input-readonly-copy [value]="getPlaylistUrl()"></my-input-readonly-copy> |
25 | </ngb-tab> | ||
26 | 13 | ||
27 | <ngb-tab i18n-title title="QR-Code" id="qrcode"> | 14 | <div class="filters"> |
28 | <ng-template ngbTabContent> | ||
29 | <div class="tab-content"> | ||
30 | <qrcode [qrdata]="getVideoUrl()" size="256" level="Q"></qrcode> | ||
31 | </div> | ||
32 | </ng-template> | ||
33 | </ngb-tab> | ||
34 | |||
35 | <ngb-tab i18n-title title="Embed" id="embed"> | ||
36 | <ng-template ngbTabContent> | ||
37 | <div class="tab-content"> | ||
38 | <div class="input-group"> | ||
39 | <input #shareInput (click)="shareInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoIframeCode()" /> | ||
40 | <div class="input-group-append"> | ||
41 | <button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | ||
42 | <span class="glyphicon glyphicon-copy"></span> | ||
43 | </button> | ||
44 | </div> | ||
45 | </div> | ||
46 | 15 | ||
47 | <div i18n *ngIf="notSecure()" class="alert alert-warning"> | 16 | <div class="form-group"> |
48 | The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). | ||
49 | </div> | ||
50 | </div> | ||
51 | </ng-template> | ||
52 | </ngb-tab> | ||
53 | |||
54 | </ngb-tabset> | ||
55 | |||
56 | <div class="filters"> | ||
57 | <div> | ||
58 | <div class="form-group start-at"> | ||
59 | <my-peertube-checkbox | 17 | <my-peertube-checkbox |
60 | inputName="startAt" [(ngModel)]="customizations.startAtCheckbox" | 18 | inputName="includeVideoInPlaylist" [(ngModel)]="includeVideoInPlaylist" |
61 | i18n-labelText labelText="Start at" | 19 | i18n-labelText labelText="Share the playlist at this video position" |
62 | ></my-peertube-checkbox> | 20 | ></my-peertube-checkbox> |
63 | |||
64 | <my-timestamp-input | ||
65 | [timestamp]="customizations.startAt" | ||
66 | [maxTimestamp]="video.duration" | ||
67 | [disabled]="!customizations.startAtCheckbox" | ||
68 | [(ngModel)]="customizations.startAt" | ||
69 | > | ||
70 | </my-timestamp-input> | ||
71 | </div> | 21 | </div> |
72 | 22 | ||
73 | <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block"> | ||
74 | <my-peertube-checkbox | ||
75 | inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox" | ||
76 | i18n-labelText labelText="Auto select subtitle" | ||
77 | ></my-peertube-checkbox> | ||
78 | |||
79 | <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }"> | ||
80 | <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox"> | ||
81 | <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option> | ||
82 | </select> | ||
83 | </div> | ||
84 | </div> | ||
85 | </div> | 23 | </div> |
24 | </div> | ||
86 | 25 | ||
87 | <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button" | ||
88 | [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"> | ||
89 | 26 | ||
90 | <ng-container *ngIf="isAdvancedCustomizationCollapsed"> | 27 | <div class="video"> |
91 | <span class="glyphicon glyphicon-menu-down"></span> | 28 | <div class="title-page title-page-single" *ngIf="hasPlaylist()" i18n>Share the video</div> |
92 | 29 | ||
93 | <ng-container i18n> | 30 | <ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)"> |
94 | More customization | ||
95 | </ng-container> | ||
96 | </ng-container> | ||
97 | 31 | ||
98 | <ng-container *ngIf="!isAdvancedCustomizationCollapsed"> | 32 | <ngb-tab i18n-title title="URL" id="url"> |
99 | <span class="glyphicon glyphicon-menu-up"></span> | 33 | <ng-template ngbTabContent> |
100 | 34 | ||
101 | <ng-container i18n> | 35 | <div class="tab-content"> |
102 | Less customization | 36 | <my-input-readonly-copy [value]="getVideoUrl()"></my-input-readonly-copy> |
103 | </ng-container> | 37 | </div> |
104 | </ng-container> | 38 | |
105 | </div> | 39 | </ng-template> |
40 | </ngb-tab> | ||
41 | |||
42 | <ngb-tab i18n-title title="QR-Code" id="qrcode"> | ||
43 | <ng-template ngbTabContent> | ||
44 | <div class="tab-content"> | ||
45 | <qrcode [qrdata]="getVideoUrl()" size="256" level="Q"></qrcode> | ||
46 | </div> | ||
47 | </ng-template> | ||
48 | </ngb-tab> | ||
106 | 49 | ||
107 | <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed"> | 50 | <ngb-tab i18n-title title="Embed" id="embed"> |
51 | <ng-template ngbTabContent> | ||
52 | <div class="tab-content"> | ||
53 | <my-input-readonly-copy [value]="getVideoIframeCode()"></my-input-readonly-copy> | ||
54 | |||
55 | <div i18n *ngIf="notSecure()" class="alert alert-warning"> | ||
56 | The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). | ||
57 | </div> | ||
58 | </div> | ||
59 | </ng-template> | ||
60 | </ngb-tab> | ||
61 | |||
62 | </ngb-tabset> | ||
63 | |||
64 | <div class="filters"> | ||
108 | <div> | 65 | <div> |
109 | <div class="form-group stop-at"> | 66 | <div class="form-group start-at"> |
110 | <my-peertube-checkbox | 67 | <my-peertube-checkbox |
111 | inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox" | 68 | inputName="startAt" [(ngModel)]="customizations.startAtCheckbox" |
112 | i18n-labelText labelText="Stop at" | 69 | i18n-labelText labelText="Start at" |
113 | ></my-peertube-checkbox> | 70 | ></my-peertube-checkbox> |
114 | 71 | ||
115 | <my-timestamp-input | 72 | <my-timestamp-input |
116 | [timestamp]="customizations.stopAt" | 73 | [timestamp]="customizations.startAt" |
117 | [maxTimestamp]="video.duration" | 74 | [maxTimestamp]="video.duration" |
118 | [disabled]="!customizations.stopAtCheckbox" | 75 | [disabled]="!customizations.startAtCheckbox" |
119 | [(ngModel)]="customizations.stopAt" | 76 | [(ngModel)]="customizations.startAt" |
120 | > | 77 | > |
121 | </my-timestamp-input> | 78 | </my-timestamp-input> |
122 | </div> | 79 | </div> |
123 | 80 | ||
124 | <div class="form-group"> | 81 | <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block"> |
125 | <my-peertube-checkbox | 82 | <my-peertube-checkbox |
126 | inputName="autoplay" [(ngModel)]="customizations.autoplay" | 83 | inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox" |
127 | i18n-labelText labelText="Autoplay" | 84 | i18n-labelText labelText="Auto select subtitle" |
128 | ></my-peertube-checkbox> | 85 | ></my-peertube-checkbox> |
129 | </div> | ||
130 | 86 | ||
131 | <div class="form-group"> | 87 | <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }"> |
132 | <my-peertube-checkbox | 88 | <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox"> |
133 | inputName="muted" [(ngModel)]="customizations.muted" | 89 | <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option> |
134 | i18n-labelText labelText="Muted" | 90 | </select> |
135 | ></my-peertube-checkbox> | 91 | </div> |
136 | </div> | 92 | </div> |
93 | </div> | ||
137 | 94 | ||
138 | <div class="form-group"> | 95 | <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button" |
139 | <my-peertube-checkbox | 96 | [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"> |
140 | inputName="loop" [(ngModel)]="customizations.loop" | 97 | |
141 | i18n-labelText labelText="Loop" | 98 | <ng-container *ngIf="isAdvancedCustomizationCollapsed"> |
142 | ></my-peertube-checkbox> | 99 | <span class="glyphicon glyphicon-menu-down"></span> |
143 | </div> | 100 | |
101 | <ng-container i18n> | ||
102 | More customization | ||
103 | </ng-container> | ||
104 | </ng-container> | ||
105 | |||
106 | <ng-container *ngIf="!isAdvancedCustomizationCollapsed"> | ||
107 | <span class="glyphicon glyphicon-menu-up"></span> | ||
108 | |||
109 | <ng-container i18n> | ||
110 | Less customization | ||
111 | </ng-container> | ||
112 | </ng-container> | ||
144 | </div> | 113 | </div> |
145 | 114 | ||
146 | <ng-container *ngIf="isInEmbedTab()"> | 115 | <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed"> |
147 | <div class="form-group"> | 116 | <div> |
148 | <my-peertube-checkbox | 117 | <div class="form-group stop-at"> |
149 | inputName="title" [(ngModel)]="customizations.title" | 118 | <my-peertube-checkbox |
150 | i18n-labelText labelText="Display video title" | 119 | inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox" |
151 | ></my-peertube-checkbox> | 120 | i18n-labelText labelText="Stop at" |
152 | </div> | 121 | ></my-peertube-checkbox> |
122 | |||
123 | <my-timestamp-input | ||
124 | [timestamp]="customizations.stopAt" | ||
125 | [maxTimestamp]="video.duration" | ||
126 | [disabled]="!customizations.stopAtCheckbox" | ||
127 | [(ngModel)]="customizations.stopAt" | ||
128 | > | ||
129 | </my-timestamp-input> | ||
130 | </div> | ||
153 | 131 | ||
154 | <div class="form-group"> | 132 | <div class="form-group"> |
155 | <my-peertube-checkbox | 133 | <my-peertube-checkbox |
156 | inputName="warningTitle" [(ngModel)]="customizations.warningTitle" | 134 | inputName="autoplay" [(ngModel)]="customizations.autoplay" |
157 | i18n-labelText labelText="Display privacy warning" | 135 | i18n-labelText labelText="Autoplay" |
158 | ></my-peertube-checkbox> | 136 | ></my-peertube-checkbox> |
159 | </div> | 137 | </div> |
160 | 138 | ||
161 | <div class="form-group"> | 139 | <div class="form-group"> |
162 | <my-peertube-checkbox | 140 | <my-peertube-checkbox |
163 | inputName="controls" [(ngModel)]="customizations.controls" | 141 | inputName="muted" [(ngModel)]="customizations.muted" |
164 | i18n-labelText labelText="Display player controls" | 142 | i18n-labelText labelText="Muted" |
165 | ></my-peertube-checkbox> | 143 | ></my-peertube-checkbox> |
144 | </div> | ||
145 | |||
146 | <div class="form-group"> | ||
147 | <my-peertube-checkbox | ||
148 | inputName="loop" [(ngModel)]="customizations.loop" | ||
149 | i18n-labelText labelText="Loop" | ||
150 | ></my-peertube-checkbox> | ||
151 | </div> | ||
166 | </div> | 152 | </div> |
167 | </ng-container> | 153 | |
154 | <ng-container *ngIf="isInEmbedTab()"> | ||
155 | <div class="form-group"> | ||
156 | <my-peertube-checkbox | ||
157 | inputName="title" [(ngModel)]="customizations.title" | ||
158 | i18n-labelText labelText="Display video title" | ||
159 | ></my-peertube-checkbox> | ||
160 | </div> | ||
161 | |||
162 | <div class="form-group"> | ||
163 | <my-peertube-checkbox | ||
164 | inputName="warningTitle" [(ngModel)]="customizations.warningTitle" | ||
165 | i18n-labelText labelText="Display privacy warning" | ||
166 | ></my-peertube-checkbox> | ||
167 | </div> | ||
168 | |||
169 | <div class="form-group"> | ||
170 | <my-peertube-checkbox | ||
171 | inputName="controls" [(ngModel)]="customizations.controls" | ||
172 | i18n-labelText labelText="Display player controls" | ||
173 | ></my-peertube-checkbox> | ||
174 | </div> | ||
175 | </ng-container> | ||
176 | </div> | ||
168 | </div> | 177 | </div> |
169 | </div> | 178 | </div> |
170 | </div> | 179 | </div> |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.scss b/client/src/app/videos/+video-watch/modal/video-share.component.scss index c48abf9e0..8b5952da6 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.scss +++ b/client/src/app/videos/+video-watch/modal/video-share.component.scss | |||
@@ -1,6 +1,18 @@ | |||
1 | @import '_mixins'; | 1 | @import '_mixins'; |
2 | @import '_variables'; | 2 | @import '_variables'; |
3 | 3 | ||
4 | my-input-readonly-copy { | ||
5 | width: 100%; | ||
6 | } | ||
7 | |||
8 | .title-page.title-page-single { | ||
9 | margin-top: 0; | ||
10 | } | ||
11 | |||
12 | .playlist { | ||
13 | margin-bottom: 50px; | ||
14 | } | ||
15 | |||
4 | .peertube-select-container { | 16 | .peertube-select-container { |
5 | @include peertube-select-container(200px); | 17 | @include peertube-select-container(200px); |
6 | } | 18 | } |
@@ -25,10 +37,6 @@ | |||
25 | margin-top: 20px; | 37 | margin-top: 20px; |
26 | } | 38 | } |
27 | 39 | ||
28 | input.readonly { | ||
29 | font-size: 15px; | ||
30 | } | ||
31 | |||
32 | .filters { | 40 | .filters { |
33 | margin-top: 30px; | 41 | margin-top: 30px; |
34 | padding-top: 30px; | 42 | padding-top: 30px; |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.ts b/client/src/app/videos/+video-watch/modal/video-share.component.ts index f45afccfb..a9a7a0eab 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-share.component.ts | |||
@@ -5,6 +5,7 @@ import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils | |||
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | 5 | import { I18n } from '@ngx-translate/i18n-polyfill' |
6 | import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap' |
7 | import { VideoCaption } from '@shared/models' | 7 | import { VideoCaption } from '@shared/models' |
8 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | ||
8 | 9 | ||
9 | type Customizations = { | 10 | type Customizations = { |
10 | startAtCheckbox: boolean | 11 | startAtCheckbox: boolean |
@@ -34,18 +35,16 @@ export class VideoShareComponent { | |||
34 | 35 | ||
35 | @Input() video: VideoDetails = null | 36 | @Input() video: VideoDetails = null |
36 | @Input() videoCaptions: VideoCaption[] = [] | 37 | @Input() videoCaptions: VideoCaption[] = [] |
38 | @Input() playlist: VideoPlaylist = null | ||
37 | 39 | ||
38 | activeId: 'url' | 'qrcode' | 'embed' | 40 | activeId: 'url' | 'qrcode' | 'embed' |
39 | customizations: Customizations | 41 | customizations: Customizations |
40 | isAdvancedCustomizationCollapsed = true | 42 | isAdvancedCustomizationCollapsed = true |
43 | includeVideoInPlaylist = false | ||
41 | 44 | ||
42 | private currentVideoTimestamp: number | 45 | private currentVideoTimestamp: number |
43 | 46 | ||
44 | constructor ( | 47 | constructor (private modalService: NgbModal) { } |
45 | private modalService: NgbModal, | ||
46 | private notifier: Notifier, | ||
47 | private i18n: I18n | ||
48 | ) { } | ||
49 | 48 | ||
50 | show (currentVideoTimestamp?: number) { | 49 | show (currentVideoTimestamp?: number) { |
51 | this.currentVideoTimestamp = currentVideoTimestamp | 50 | this.currentVideoTimestamp = currentVideoTimestamp |
@@ -86,17 +85,22 @@ export class VideoShareComponent { | |||
86 | } | 85 | } |
87 | 86 | ||
88 | getVideoUrl () { | 87 | getVideoUrl () { |
89 | const options = this.getOptions() | 88 | const baseUrl = window.location.origin + '/videos/watch/' + this.video.uuid |
89 | const options = this.getOptions(baseUrl) | ||
90 | 90 | ||
91 | return buildVideoLink(options) | 91 | return buildVideoLink(options) |
92 | } | 92 | } |
93 | 93 | ||
94 | notSecure () { | 94 | getPlaylistUrl () { |
95 | return window.location.protocol === 'http:' | 95 | const base = window.location.origin + '/videos/watch/playlist/' + this.playlist.uuid |
96 | |||
97 | if (!this.includeVideoInPlaylist) return base | ||
98 | |||
99 | return base + '?videoId=' + this.video.uuid | ||
96 | } | 100 | } |
97 | 101 | ||
98 | activateCopiedMessage () { | 102 | notSecure () { |
99 | this.notifier.success(this.i18n('Copied')) | 103 | return window.location.protocol === 'http:' |
100 | } | 104 | } |
101 | 105 | ||
102 | onTabChange (event: NgbTabChangeEvent) { | 106 | onTabChange (event: NgbTabChangeEvent) { |
@@ -107,6 +111,10 @@ export class VideoShareComponent { | |||
107 | return this.activeId === 'embed' | 111 | return this.activeId === 'embed' |
108 | } | 112 | } |
109 | 113 | ||
114 | hasPlaylist () { | ||
115 | return !!this.playlist | ||
116 | } | ||
117 | |||
110 | private getOptions (baseUrl?: string) { | 118 | private getOptions (baseUrl?: string) { |
111 | return { | 119 | return { |
112 | baseUrl, | 120 | baseUrl, |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 38ad4e948..5b2e91bc5 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -224,5 +224,5 @@ | |||
224 | 224 | ||
225 | <ng-container *ngIf="video !== null"> | 225 | <ng-container *ngIf="video !== null"> |
226 | <my-video-support #videoSupportModal [video]="video"></my-video-support> | 226 | <my-video-support #videoSupportModal [video]="video"></my-video-support> |
227 | <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions"></my-video-share> | 227 | <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share> |
228 | </ng-container> | 228 | </ng-container> |