aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/menu
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/menu')
-rw-r--r--client/src/app/menu/avatar-notification.component.html2
-rw-r--r--client/src/app/menu/avatar-notification.component.ts1
-rw-r--r--client/src/app/menu/language-chooser.component.scss7
-rw-r--r--client/src/app/menu/language-chooser.component.ts18
-rw-r--r--client/src/app/menu/menu.component.html103
-rw-r--r--client/src/app/menu/menu.component.scss207
-rw-r--r--client/src/app/menu/menu.component.ts100
7 files changed, 343 insertions, 95 deletions
diff --git a/client/src/app/menu/avatar-notification.component.html b/client/src/app/menu/avatar-notification.component.html
index 7975afba5..df2a102a3 100644
--- a/client/src/app/menu/avatar-notification.component.html
+++ b/client/src/app/menu/avatar-notification.component.html
@@ -30,7 +30,7 @@
30 </div> 30 </div>
31 31
32 <my-user-notifications 32 <my-user-notifications
33 [ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10" 33 [ignoreLoadingBar]="true" [infiniteScroll]="false" [itemsPerPage]="10"
34 [markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()" 34 [markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
35 ></my-user-notifications> 35 ></my-user-notifications>
36 36
diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts
index 989a11849..c447f031c 100644
--- a/client/src/app/menu/avatar-notification.component.ts
+++ b/client/src/app/menu/avatar-notification.component.ts
@@ -6,7 +6,6 @@ import { Notifier, UserNotificationSocket } from '@app/core'
6import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' 6import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
7import { NavigationEnd, Router } from '@angular/router' 7import { NavigationEnd, Router } from '@angular/router'
8import { filter } from 'rxjs/operators' 8import { filter } from 'rxjs/operators'
9import { UserNotificationsComponent } from '@app/shared'
10 9
11@Component({ 10@Component({
12 selector: 'my-avatar-notification', 11 selector: 'my-avatar-notification',
diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss
index 72deb3952..6226a85cb 100644
--- a/client/src/app/menu/language-chooser.component.scss
+++ b/client/src/app/menu/language-chooser.component.scss
@@ -4,6 +4,13 @@
4.help-to-translate { 4.help-to-translate {
5 @include peertube-button-link; 5 @include peertube-button-link;
6 @include orange-button; 6 @include orange-button;
7
8 &.focus-visible,
9 &:focus {
10 box-shadow: none;
11 }
12
13 border-radius: 0;
7} 14}
8 15
9.modal-body { 16.modal-body {
diff --git a/client/src/app/menu/language-chooser.component.ts b/client/src/app/menu/language-chooser.component.ts
index 4a6e4c75a..9bc934ad4 100644
--- a/client/src/app/menu/language-chooser.component.ts
+++ b/client/src/app/menu/language-chooser.component.ts
@@ -1,7 +1,9 @@
1import { Component, ElementRef, ViewChild } from '@angular/core' 1import { Component, ElementRef, ViewChild, Inject, LOCALE_ID } from '@angular/core'
2import { I18N_LOCALES } from '../../../../shared' 2import { I18N_LOCALES } from '../../../../shared'
3import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 3import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
4import { sortBy } from '@app/shared/misc/utils' 4import { sortBy } from '@app/shared/misc/utils'
5import { getCompleteLocale } from '@shared/models/i18n'
6import { isOnDevLocale, getDevLocale } from '@app/shared/i18n/i18n-utils'
5 7
6@Component({ 8@Component({
7 selector: 'my-language-chooser', 9 selector: 'my-language-chooser',
@@ -13,7 +15,10 @@ export class LanguageChooserComponent {
13 15
14 languages: { id: string, label: string }[] = [] 16 languages: { id: string, label: string }[] = []
15 17
16 constructor (private modalService: NgbModal) { 18 constructor (
19 private modalService: NgbModal,
20 @Inject(LOCALE_ID) private localeId: string
21 ) {
17 const l = Object.keys(I18N_LOCALES) 22 const l = Object.keys(I18N_LOCALES)
18 .map(k => ({ id: k, label: I18N_LOCALES[k] })) 23 .map(k => ({ id: k, label: I18N_LOCALES[k] }))
19 24
@@ -21,11 +26,18 @@ export class LanguageChooserComponent {
21 } 26 }
22 27
23 show () { 28 show () {
24 this.modalService.open(this.modal) 29 this.modalService.open(this.modal, { centered: true })
25 } 30 }
26 31
27 buildLanguageLink (lang: { id: string }) { 32 buildLanguageLink (lang: { id: string }) {
28 return window.location.origin + '/' + lang.id 33 return window.location.origin + '/' + lang.id
29 } 34 }
30 35
36 getCurrentLanguage () {
37 const english = 'English'
38 const locale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
39
40 if (locale) return I18N_LOCALES[locale] || english
41 return english
42 }
31} 43}
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index 675fb597d..1cb51ef55 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -8,34 +8,65 @@
8 <a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a> 8 <a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a>
9 <a *ngIf="!user.account" routerLink="/my-account/settings" class="logged-in-display-name">{{ user.account?.displayName }}</a> 9 <a *ngIf="!user.account" routerLink="/my-account/settings" class="logged-in-display-name">{{ user.account?.displayName }}</a>
10 10
11 <div ngxClipboard [cbContent]="user.account?.nameWithHost" class="logged-in-username">{{ user.username }}</div> 11 <div class="logged-in-username">{{ user.username }}</div>
12 </div> 12 </div>
13 13
14 <div class="logged-in-more" ngbDropdown placement="bottom-right auto"> 14 <div class="logged-in-more" ngbDropdown [placement]="placement" container="body" autoClose="outside">
15 <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button"></my-global-icon> 15 <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button"></my-global-icon>
16 16
17 <div ngbDropdownMenu> 17 <div ngbDropdownMenu>
18 <a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="dropdown-item"> 18 <a *ngIf="user.account" ngbDropdownItem ngbDropdownToggle class="dropdown-item" [routerLink]="[ '/accounts', user.account.nameWithHost ]">
19 <my-global-icon iconName="go"></my-global-icon> <ng-container i18n>Public profile</ng-container> 19 <my-global-icon iconName="go"></my-global-icon> <ng-container i18n>Public profile</ng-container>
20 </a> 20 </a>
21 21
22 <div class="dropdown-divider"></div> 22 <div class="dropdown-divider"></div>
23 23
24 <a routerLink="/my-account" class="dropdown-item"> 24 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account">
25 <my-global-icon iconName="user"></my-global-icon> <ng-container i18n>Account settings</ng-container> 25 <my-global-icon iconName="user"></my-global-icon> <ng-container i18n>Account settings</ng-container>
26 </a> 26 </a>
27 27
28 <a routerLink="/my-account/video-channels" class="dropdown-item"> 28 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/video-channels">
29 <my-global-icon iconName="folder"></my-global-icon> <ng-container i18n>Channels settings</ng-container> 29 <my-global-icon iconName="folder"></my-global-icon> <ng-container i18n>Channels settings</ng-container>
30 </a> 30 </a>
31 31
32 <div class="dropdown-divider"></div> 32 <div class="dropdown-divider"></div>
33 33
34 <a class="dropdown-item" href="https://joinpeertube.org/help" target="_blank" rel="noopener noreferrer"> 34 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openLanguageChooser()">
35 <my-global-icon iconName="help"></my-global-icon> <ng-container i18n>Help</ng-container> 35 <my-global-icon iconName="language"></my-global-icon>
36 <ng-container i18n>Interface: {{ language }}</ng-container>
37 <i class="ml-auto glyphicon glyphicon-menu-right"></i>
36 </a> 38 </a>
37 39
38 <a (click)="logout($event)" class="dropdown-item" href="#"> 40 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-settings">
41 <my-global-icon iconName="video-lang"></my-global-icon>
42 <ng-container i18n>Videos: {{ videoLanguages.join(', ') }}</ng-container>
43 <i class="ml-auto glyphicon glyphicon-menu-right"></i>
44 </a>
45
46 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-settings">
47 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy === 'display' }" iconName="sensitive"></my-global-icon>
48 <my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy !== 'display' }" iconName="unsensitive"></my-global-icon>
49 <ng-container i18n>Sensitive: {{ nsfwPolicy }}</ng-container>
50 <i class="ml-auto glyphicon glyphicon-menu-right"></i>
51 </a>
52
53 <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()">
54 <my-global-icon iconName="p2p"></my-global-icon>
55 <ng-container i18n>Help share videos</ng-container>
56 <input type="checkbox" [checked]="user.webTorrentEnabled"/><label class="ml-auto" for="switch">Toggle p2p</label>
57 </a>
58
59 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account">
60 <my-global-icon iconName="more-horizontal"></my-global-icon> <ng-container i18n>More account settings</ng-container>
61 </a>
62
63 <div class="dropdown-divider"></div>
64
65 <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openHotkeysCheatSheet()">
66 <i class="icon icon-shortcuts"></i> <ng-container i18n>Keyboard shortcuts</ng-container>
67 </a>
68
69 <a ngbDropdownItem ngbDropdownToggle (click)="logout($event)" class="dropdown-item" href="#">
39 <my-global-icon iconName="sign-out"></my-global-icon> <ng-container i18n>Log out</ng-container> 70 <my-global-icon iconName="sign-out"></my-global-icon> <ng-container i18n>Log out</ng-container>
40 </a> 71 </a>
41 </div> 72 </div>
@@ -48,7 +79,7 @@
48 </div> 79 </div>
49 80
50 <div *ngIf="isLoggedIn" class="panel-block"> 81 <div *ngIf="isLoggedIn" class="panel-block">
51 <div i18n class="block-title">My library</div> 82 <div i18n class="block-title">MY LIBRARY</div>
52 83
53 <a routerLink="/my-account/videos" routerLinkActive="active"> 84 <a routerLink="/my-account/videos" routerLinkActive="active">
54 <my-global-icon iconName="videos"></my-global-icon> 85 <my-global-icon iconName="videos"></my-global-icon>
@@ -73,7 +104,7 @@
73 </div> 104 </div>
74 105
75 <div class="panel-block"> 106 <div class="panel-block">
76 <div i18n class="block-title">Videos</div> 107 <div i18n class="block-title">VIDEOS</div>
77 108
78 <a routerLink="/videos/overview" routerLinkActive="active"> 109 <a routerLink="/videos/overview" routerLinkActive="active">
79 <my-global-icon iconName="globe"></my-global-icon> 110 <my-global-icon iconName="globe"></my-global-icon>
@@ -100,32 +131,56 @@
100 <ng-container i18n>Local</ng-container> 131 <ng-container i18n>Local</ng-container>
101 </a> 132 </a>
102 </div> 133 </div>
134 </div>
103 135
136 <div class="footer">
104 <div class="panel-block"> 137 <div class="panel-block">
105 <div class="block-title" i18n>More</div>
106
107 <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> 138 <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active">
108 <my-global-icon iconName="administration"></my-global-icon> 139 <my-global-icon iconName="cog"></my-global-icon>
109 <ng-container i18n>Administration</ng-container> 140 <ng-container i18n>Administration</ng-container>
110 </a> 141 </a>
111 142 <a *ngIf="!isLoggedIn" (click)="openQuickSettings()">
112 <a routerLink="/about" routerLinkActive="active"> 143 <my-global-icon iconName="cog"></my-global-icon>
113 <my-global-icon iconName="about"></my-global-icon> 144 <ng-container i18n>Settings</ng-container>
145 </a>
146 <a routerLink="/about/instance">
147 <my-global-icon iconName="help"></my-global-icon>
114 <ng-container i18n>About</ng-container> 148 <ng-container i18n>About</ng-container>
115 </a> 149 </a>
116 </div> 150 </div>
117 </div>
118 151
119 <div class="footer d-flex justify-content-between"> 152 <div class="bottom-links">
120 <span class="language">
121 <span tabindex="0" role="button" (keyup.enter)="openLanguageChooser()" (click)="openLanguageChooser()" i18n-title title="Change the language" class="icon icon-language"></span>
122 </span>
123 153
124 <span class="shortcuts"> 154 <div class="footer-links">
125 <span tabindex="0" role="button" (keyup.enter)="openHotkeysCheatSheet()" (click)="openHotkeysCheatSheet()" i18n-title title="Show keyboard shortcuts" class="icon icon-shortcuts"></span> 155 <div *ngIf="isLoggedIn === false">
126 </span> 156 <span role="button" (click)="openLanguageChooser()" class="c-hand" i18n>Interface: {{ language }}</span>
157 </div>
158
159 <div>
160 <a i18n routerLink="/about/instance">Contact</a>
161 <a i18n href="https://joinpeertube.org/help" i18n-title title="Get help using PeerTube" target="_blank" rel="noopener noreferrer">Help</a>
162 <a i18n href="https://joinpeertube.org/faq" i18n-title title="Frequently asked questions about PeerTube" target="_blank" rel="noopener noreferrer">FAQ</a>
163 <a i18n routerLink="/about/instance" fragment="statistics">Stats</a>
164 <a i18n href="https://docs.joinpeertube.org/api-rest-reference.html" i18n-title title="API documentation" target="_blank" rel="noopener noreferrer">API</a>
165 <a (click)="openHotkeysCheatSheet()" class="c-hand" i18n>Shortcuts</a>
166 </div>
167 </div>
168
169 <div class="footer-copyleft">
170 <small class="d-inline" i18n-title title="powered by PeerTube - CopyLeft 2015-2020">
171 <a href="https://joinpeertube.org" i18n-title title="PeerTube website" target="_blank" rel="noopener noreferrer" i18n>
172 powered by PeerTube
173 </a>
174
175 <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/LICENSE" i18n-title title="PeerTube license" target="_blank" rel="noopener noreferrer">
176 <span aria-label="copyleft" class="d-inline-block" style="transform: rotateY(180deg)">&copy;</span> 2015-2020
177 </a>
178 </small>
179 </div>
180 </div>
127 </div> 181 </div>
128 </menu> 182 </menu>
129</div> 183</div>
130 184
131<my-language-chooser #languageChooserModal></my-language-chooser> 185<my-language-chooser #languageChooserModal></my-language-chooser>
186<my-quick-settings #quickSettingsModal></my-quick-settings>
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index b05173751..5bff0c328 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -6,7 +6,8 @@
6 height: calc(100vh - #{$header-height}); 6 height: calc(100vh - #{$header-height});
7 padding: 0; 7 padding: 0;
8 width: $menu-width; 8 width: $menu-width;
9 z-index: 10000; 9 z-index: z(menu);
10 scrollbar-color: var(--actionButtonColor) var(--menuBackgroundColor);
10} 11}
11 12
12menu { 13menu {
@@ -26,9 +27,13 @@ menu {
26 overflow-y: auto; 27 overflow-y: auto;
27 } 28 }
28 29
30 @media not all and (hover: hover) and (pointer: fine) {
31 overflow-y: auto;
32 }
33
29 &.logged-in { 34 &.logged-in {
30 .panel-block { 35 .panel-block {
31 margin-bottom: 25px; 36 margin-bottom: 20px;
32 } 37 }
33 38
34 .block-title { 39 .block-title {
@@ -87,22 +92,6 @@ menu {
87 @include apply-svg-color(var(--menuForegroundColor)); 92 @include apply-svg-color(var(--menuForegroundColor));
88 } 93 }
89 } 94 }
90
91 .dropdown-item {
92 @include dropdown-with-icon-item;
93
94 my-global-icon {
95 width: 22px;
96 height: 22px;
97
98 &[iconName="sign-out"] {
99 position: relative;
100 right: -1px;
101 height: 21px;
102 width: 21px;
103 }
104 }
105 }
106 } 95 }
107 } 96 }
108 97
@@ -142,7 +131,7 @@ menu {
142 } 131 }
143 132
144 .panel-block { 133 .panel-block {
145 margin-bottom: 45px; 134 margin-bottom: 15px;
146 135
147 a { 136 a {
148 @include disable-default-a-behaviour; 137 @include disable-default-a-behaviour;
@@ -197,58 +186,160 @@ menu {
197 } 186 }
198 187
199 .footer { 188 .footer {
200 padding-bottom: 15px;
201 padding-left: $menu-lateral-padding;
202 padding-right: $menu-lateral-padding;
203 width: $menu-width; 189 width: $menu-width;
190 padding-bottom: 15px;
204 191
205 .language, .shortcuts, .color-palette { 192 .bottom-links {
206 display: inline-block; 193 display: flex;
207 color: $menu-bottom-color; 194 flex-direction: column;
208 cursor: pointer; 195 padding: 0 $menu-lateral-padding;
209 font-size: 12px; 196 }
210 font-weight: $font-semibold;
211 197
212 .icon { 198 $footer-links-base-opacity: .8;
213 @include disable-outline;
214 @include icon(28px);
215 opacity: 0.9;
216 199
217 &.icon-language { 200 .footer-links {
218 position: relative; 201 &, > div {
219 top: -1px; 202 display: flex;
220 width: 28px; 203 flex-wrap: wrap;
221 height: 24px; 204 }
222 205
223 background-image: url('../../assets/images/menu/language.png'); 206 a, span[role=button] {
207 display: inline-block;
208 text-decoration: none;
209 color: var(--mainBackgroundColor);
210 opacity: $footer-links-base-opacity;
211 white-space: nowrap;
212 font-size: 90%;
213 font-weight: 500;
214 line-height: 1.4rem;
215 margin-right: 8px;
216
217 &.inline-global-icon {
218 display: inline-flex;
219 align-items: center;
220 white-space: nowrap;
221 height: 1.4rem;
222
223 my-global-icon {
224 @include apply-svg-color(var(--mainBackgroundColor));
225
226 display: flex;
227 width: auto;
228 height: 90%;
229 margin-right: .2rem;
230 }
224 } 231 }
232 }
233 }
225 234
226 &.icon-shortcuts { 235 .footer-copyleft small a {
227 position: relative; 236 @include disable-default-a-behaviour;
228 top: -1px;
229 width: 24px;
230 height: 24px;
231 237
232 background-image: url('../../assets/images/menu/keyboard.png'); 238 color: var(--mainBackgroundColor);
233 filter: invert(100%); 239 opacity: $footer-links-base-opacity - .2;
234 } 240 }
241 }
242}
235 243
236 &.icon-moonsun { 244.dropdown-menu {
237 margin-left: 10px; 245 width: calc(100% + 40px);
238 position: relative; 246}
239 top: -1px;
240 width: 24px;
241 height: 24px;
242 247
243 background-image: url('../../assets/images/menu/moonsun.svg'); 248.dropdown-item {
244 } 249 @include dropdown-with-icon-item;
245 250
246 &:hover { 251 cursor: pointer;
247 opacity: 1; 252 display: flex;
248 } 253 align-items: center;
249 } 254
255 i.glyphicon-menu-right {
256 opacity: .4;
257 }
258
259 my-global-icon {
260 &[iconName="cog"],
261 &[iconName="sign-out"] {
262 position: relative;
263 right: -2px;
264 height: 20px;
265 width: 20px;
250 } 266 }
251 } 267 }
268
269 my-global-icon.not-displayed {
270 display: none;
271 }
272
273 &:hover {
274 my-global-icon.hover-display-toggle.not-displayed {
275 display: inherit;
276 }
277 my-global-icon.hover-display-toggle {
278 display: none;
279 }
280 }
281}
282
283.more-settings {
284 text-transform: uppercase;
285 font-size: 80%;
286 color: #6c757d;
287}
288
289.icon {
290 @include disable-outline;
291 @include icon(22px);
292 opacity: 0.8;
293
294 &.icon-shortcuts {
295 position: relative;
296 top: -1px;
297 margin-right: 10px;
298
299 background-image: url('../../assets/images/menu/keyboard.png');
300 }
301}
302
303input[type=checkbox]{
304 position: absolute;
305 visibility: hidden;
306}
307
308label {
309 cursor: pointer;
310 text-indent: -9999px;
311 width: 35px;
312 height: 20px;
313 background: #cccccc;
314 display: block;
315 border-radius: 100px;
316 position: relative;
317 margin: 0;
318
319 &:after {
320 content: '';
321 position: absolute;
322 top: 3px;
323 left: 3px;
324 width: 14px;
325 height: 14px;
326 background: var(--mainBackgroundColor);
327 border-radius: 50%;
328 transition: 0.3s ease-out;
329 }
330
331 &:active:after {
332 width: 40px;
333 }
334}
335
336input:checked + label {
337 background: var(--mainColor);
338
339 &:after {
340 left: calc(100% - 3px);
341 transform: translateX(-100%);
342 }
252} 343}
253 344
254@media screen and (max-width: $mobile-view) { 345@media screen and (max-width: $mobile-view) {
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
index 1d7651e78..015c14bce 100644
--- a/client/src/app/menu/menu.component.ts
+++ b/client/src/app/menu/menu.component.ts
@@ -1,10 +1,14 @@
1import { Component, OnInit, ViewChild } from '@angular/core' 1import { Component, OnInit, ViewChild } from '@angular/core'
2import { UserRight } from '../../../../shared/models/users/user-right.enum' 2import { UserRight } from '../../../../shared/models/users/user-right.enum'
3import { AuthService, AuthStatus, RedirectService, ServerService, ThemeService } from '../core' 3import { AuthService, AuthStatus, RedirectService, ServerService } from '../core'
4import { User } from '../shared/users/user.model' 4import { User } from '@app/shared/users/user.model'
5import { UserService } from '@app/shared/users/user.service'
5import { LanguageChooserComponent } from '@app/menu/language-chooser.component' 6import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
6import { HotkeysService } from 'angular2-hotkeys' 7import { HotkeysService } from 'angular2-hotkeys'
7import { ServerConfig } from '@shared/models' 8import { ServerConfig, VideoConstant } from '@shared/models'
9import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
10import { I18n } from '@ngx-translate/i18n-polyfill'
11import { ScreenService } from '@app/shared/misc/screen.service'
8 12
9@Component({ 13@Component({
10 selector: 'my-menu', 14 selector: 'my-menu',
@@ -13,12 +17,17 @@ import { ServerConfig } from '@shared/models'
13}) 17})
14export class MenuComponent implements OnInit { 18export class MenuComponent implements OnInit {
15 @ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent 19 @ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
20 @ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
16 21
17 user: User 22 user: User
18 isLoggedIn: boolean 23 isLoggedIn: boolean
24
19 userHasAdminAccess = false 25 userHasAdminAccess = false
20 helpVisible = false 26 helpVisible = false
21 27
28 videoLanguages: string[] = []
29
30 private languages: VideoConstant<string>[] = []
22 private serverConfig: ServerConfig 31 private serverConfig: ServerConfig
23 private routesPerRight: { [ role in UserRight ]?: string } = { 32 private routesPerRight: { [ role in UserRight ]?: string } = {
24 [UserRight.MANAGE_USERS]: '/admin/users', 33 [UserRight.MANAGE_USERS]: '/admin/users',
@@ -31,10 +40,25 @@ export class MenuComponent implements OnInit {
31 40
32 constructor ( 41 constructor (
33 private authService: AuthService, 42 private authService: AuthService,
43 private userService: UserService,
34 private serverService: ServerService, 44 private serverService: ServerService,
35 private redirectService: RedirectService, 45 private redirectService: RedirectService,
36 private hotkeysService: HotkeysService 46 private hotkeysService: HotkeysService,
37 ) {} 47 private screenService: ScreenService,
48 private i18n: I18n
49 ) { }
50
51 get isInMobileView () {
52 return this.screenService.isInMobileView()
53 }
54
55 get placement () {
56 if (this.isInMobileView) {
57 return 'left-top auto'
58 } else {
59 return 'right-top auto'
60 }
61 }
38 62
39 ngOnInit () { 63 ngOnInit () {
40 this.serverConfig = this.serverService.getTmpConfig() 64 this.serverConfig = this.serverService.getTmpConfig()
@@ -63,9 +87,35 @@ export class MenuComponent implements OnInit {
63 } 87 }
64 ) 88 )
65 89
66 this.hotkeysService.cheatSheetToggle.subscribe(isOpen => { 90 this.hotkeysService.cheatSheetToggle
67 this.helpVisible = isOpen 91 .subscribe(isOpen => this.helpVisible = isOpen)
68 }) 92
93 this.serverService.getVideoLanguages()
94 .subscribe(languages => {
95 this.languages = languages
96
97 this.authService.userInformationLoaded
98 .subscribe(() => this.buildUserLanguages())
99 })
100 }
101
102 get language () {
103 return this.languageChooserModal.getCurrentLanguage()
104 }
105
106 get nsfwPolicy () {
107 if (!this.user) return
108
109 switch (this.user.nsfwPolicy) {
110 case 'do_not_list':
111 return this.i18n('hide')
112
113 case 'blur':
114 return this.i18n('blur')
115
116 case 'display':
117 return this.i18n('display')
118 }
69 } 119 }
70 120
71 isRegistrationAllowed () { 121 isRegistrationAllowed () {
@@ -117,6 +167,40 @@ export class MenuComponent implements OnInit {
117 this.hotkeysService.cheatSheetToggle.next(!this.helpVisible) 167 this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
118 } 168 }
119 169
170 openQuickSettings () {
171 this.quickSettingsModal.show()
172 }
173
174 toggleUseP2P () {
175 if (!this.user) return
176 this.user.webTorrentEnabled = !this.user.webTorrentEnabled
177
178 this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
179 .subscribe(() => this.authService.refreshUserInformation())
180 }
181
182 langForLocale (localeId: string) {
183 if (localeId === '_unknown') return this.i18n('Unknown')
184
185 return this.languages.find(lang => lang.id === localeId).label
186 }
187
188 private buildUserLanguages () {
189 if (!this.user) {
190 this.videoLanguages = []
191 return
192 }
193
194 if (!this.user.videoLanguages) {
195 this.videoLanguages = [ this.i18n('any language') ]
196 return
197 }
198
199 this.videoLanguages = this.user.videoLanguages
200 .map(locale => this.langForLocale(locale))
201 .map(value => value === undefined ? '?' : value)
202 }
203
120 private computeIsUserHasAdminAccess () { 204 private computeIsUserHasAdminAccess () {
121 const right = this.getFirstAdminRightAvailable() 205 const right = this.getFirstAdminRightAvailable()
122 206