aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/app/app.component.ts6
-rw-r--r--client/src/app/core/menu/menu.component.html5
-rw-r--r--client/src/app/core/server/server.service.ts14
-rw-r--r--client/src/app/shared/forms/form-validators/video.ts7
-rw-r--r--client/src/app/shared/search/search-field.type.ts2
-rw-r--r--client/src/app/shared/search/search.component.html4
-rw-r--r--client/src/app/shared/search/search.component.ts17
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.html12
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.ts10
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.html12
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.ts20
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.html11
-rw-r--r--client/src/app/videos/shared/video-details.model.ts7
-rw-r--r--client/src/app/videos/shared/video-edit.model.ts6
-rw-r--r--client/src/app/videos/shared/video.service.ts55
-rw-r--r--client/src/app/videos/video-list/index.ts5
-rw-r--r--client/src/app/videos/video-list/my-videos.component.ts36
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.html (renamed from client/src/app/videos/video-list/video-list.component.html)0
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.scss (renamed from client/src/app/videos/video-list/video-list.component.scss)0
-rw-r--r--client/src/app/videos/video-list/shared/abstract-video-list.ts104
-rw-r--r--client/src/app/videos/video-list/shared/index.ts4
-rw-r--r--client/src/app/videos/video-list/shared/loader.component.html (renamed from client/src/app/videos/video-list/loader.component.html)0
-rw-r--r--client/src/app/videos/video-list/shared/loader.component.ts (renamed from client/src/app/videos/video-list/loader.component.ts)0
-rw-r--r--client/src/app/videos/video-list/shared/video-miniature.component.html (renamed from client/src/app/videos/video-list/video-miniature.component.html)0
-rw-r--r--client/src/app/videos/video-list/shared/video-miniature.component.scss (renamed from client/src/app/videos/video-list/video-miniature.component.scss)0
-rw-r--r--client/src/app/videos/video-list/shared/video-miniature.component.ts (renamed from client/src/app/videos/video-list/video-miniature.component.ts)4
-rw-r--r--client/src/app/videos/video-list/shared/video-sort.component.html (renamed from client/src/app/videos/video-list/video-sort.component.html)0
-rw-r--r--client/src/app/videos/video-list/shared/video-sort.component.ts (renamed from client/src/app/videos/video-list/video-sort.component.ts)2
-rw-r--r--client/src/app/videos/video-list/video-list.component.ts102
-rw-r--r--client/src/app/videos/videos-routing.module.ts11
-rw-r--r--client/src/app/videos/videos.module.ts9
-rw-r--r--client/src/sass/video-js-custom.scss59
32 files changed, 346 insertions, 178 deletions
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index 984470d69..bef1599fc 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -1,4 +1,4 @@
1import { Component, OnInit, ViewContainerRef } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3 3
4import { AuthService, ServerService } from './core' 4import { AuthService, ServerService } from './core'
@@ -28,8 +28,7 @@ export class AppComponent implements OnInit {
28 constructor ( 28 constructor (
29 private router: Router, 29 private router: Router,
30 private authService: AuthService, 30 private authService: AuthService,
31 private serverService: ServerService, 31 private serverService: ServerService
32 private userService: UserService
33 ) {} 32 ) {}
34 33
35 ngOnInit () { 34 ngOnInit () {
@@ -45,6 +44,7 @@ export class AppComponent implements OnInit {
45 this.serverService.loadVideoCategories() 44 this.serverService.loadVideoCategories()
46 this.serverService.loadVideoLanguages() 45 this.serverService.loadVideoLanguages()
47 this.serverService.loadVideoLicences() 46 this.serverService.loadVideoLicences()
47 this.serverService.loadVideoPrivacies()
48 48
49 // Do not display menu on small screens 49 // Do not display menu on small screens
50 if (window.innerWidth < 600) { 50 if (window.innerWidth < 600) {
diff --git a/client/src/app/core/menu/menu.component.html b/client/src/app/core/menu/menu.component.html
index 2d8aace54..fcde23fdd 100644
--- a/client/src/app/core/menu/menu.component.html
+++ b/client/src/app/core/menu/menu.component.html
@@ -23,6 +23,11 @@
23 <span class="hidden-xs glyphicon glyphicon-user"></span> 23 <span class="hidden-xs glyphicon glyphicon-user"></span>
24 My account 24 My account
25 </a> 25 </a>
26
27 <a *ngIf="isLoggedIn" routerLink="/videos/mine" routerLinkActive="active">
28 <span class="hidden-xs glyphicon glyphicon-folder-open"></span>
29 My videos
30 </a>
26 </div> 31 </div>
27 32
28 <div class="panel-block"> 33 <div class="panel-block">
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index ae507afce..cbc4074c9 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -19,6 +19,7 @@ export class ServerService {
19 private videoCategories: Array<{ id: number, label: string }> = [] 19 private videoCategories: Array<{ id: number, label: string }> = []
20 private videoLicences: Array<{ id: number, label: string }> = [] 20 private videoLicences: Array<{ id: number, label: string }> = []
21 private videoLanguages: Array<{ id: number, label: string }> = [] 21 private videoLanguages: Array<{ id: number, label: string }> = []
22 private videoPrivacies: Array<{ id: number, label: string }> = []
22 23
23 constructor (private http: HttpClient) {} 24 constructor (private http: HttpClient) {}
24 25
@@ -39,6 +40,10 @@ export class ServerService {
39 return this.loadVideoAttributeEnum('languages', this.videoLanguages) 40 return this.loadVideoAttributeEnum('languages', this.videoLanguages)
40 } 41 }
41 42
43 loadVideoPrivacies () {
44 return this.loadVideoAttributeEnum('privacies', this.videoPrivacies)
45 }
46
42 getConfig () { 47 getConfig () {
43 return this.config 48 return this.config
44 } 49 }
@@ -55,7 +60,14 @@ export class ServerService {
55 return this.videoLanguages 60 return this.videoLanguages
56 } 61 }
57 62
58 private loadVideoAttributeEnum (attributeName: 'categories' | 'licences' | 'languages', hashToPopulate: { id: number, label: string }[]) { 63 getVideoPrivacies () {
64 return this.videoPrivacies
65 }
66
67 private loadVideoAttributeEnum (
68 attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
69 hashToPopulate: { id: number, label: string }[]
70 ) {
59 return this.http.get(ServerService.BASE_VIDEO_URL + attributeName) 71 return this.http.get(ServerService.BASE_VIDEO_URL + attributeName)
60 .subscribe(data => { 72 .subscribe(data => {
61 Object.keys(data) 73 Object.keys(data)
diff --git a/client/src/app/shared/forms/form-validators/video.ts b/client/src/app/shared/forms/form-validators/video.ts
index 434773501..65f11f5da 100644
--- a/client/src/app/shared/forms/form-validators/video.ts
+++ b/client/src/app/shared/forms/form-validators/video.ts
@@ -9,6 +9,13 @@ export const VIDEO_NAME = {
9 } 9 }
10} 10}
11 11
12export const VIDEO_PRIVACY = {
13 VALIDATORS: [ Validators.required ],
14 MESSAGES: {
15 'required': 'Video privacy is required.'
16 }
17}
18
12export const VIDEO_CATEGORY = { 19export const VIDEO_CATEGORY = {
13 VALIDATORS: [ Validators.required ], 20 VALIDATORS: [ Validators.required ],
14 MESSAGES: { 21 MESSAGES: {
diff --git a/client/src/app/shared/search/search-field.type.ts b/client/src/app/shared/search/search-field.type.ts
index 63557898a..ff0bb8de1 100644
--- a/client/src/app/shared/search/search-field.type.ts
+++ b/client/src/app/shared/search/search-field.type.ts
@@ -1 +1 @@
export type SearchField = 'name' | 'author' | 'host' | 'magnetUri' | 'tags' export type SearchField = 'name' | 'author' | 'host' | 'tags'
diff --git a/client/src/app/shared/search/search.component.html b/client/src/app/shared/search/search.component.html
index c6c6ff6a8..0302447d0 100644
--- a/client/src/app/shared/search/search.component.html
+++ b/client/src/app/shared/search/search.component.html
@@ -6,12 +6,12 @@
6 6
7 <input 7 <input
8 type="text" id="search-video" name="search-video" class="form-control" placeholder="Search" class="form-control" 8 type="text" id="search-video" name="search-video" class="form-control" placeholder="Search" class="form-control"
9 [(ngModel)]="searchCriterias.value" (keyup.enter)="doSearch()" 9 [(ngModel)]="searchCriteria.value" (keyup.enter)="doSearch()"
10 > 10 >
11 11
12 <div class="input-group-btn" dropdown placement="bottom right"> 12 <div class="input-group-btn" dropdown placement="bottom right">
13 <button id="simple-btn-keyboard-nav" type="button" class="btn btn-default" dropdownToggle> 13 <button id="simple-btn-keyboard-nav" type="button" class="btn btn-default" dropdownToggle>
14 {{ getStringChoice(searchCriterias.field) }} <span class="caret"></span> 14 {{ getStringChoice(searchCriteria.field) }} <span class="caret"></span>
15 </button> 15 </button>
16 <ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="simple-btn-keyboard-nav" *dropdownMenu> 16 <ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="simple-btn-keyboard-nav" *dropdownMenu>
17 <li *ngFor="let choice of choiceKeys" class="dropdown-item" role="menu-item"> 17 <li *ngFor="let choice of choiceKeys" class="dropdown-item" role="menu-item">
diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts
index ecce20666..6e2827fe3 100644
--- a/client/src/app/shared/search/search.component.ts
+++ b/client/src/app/shared/search/search.component.ts
@@ -16,10 +16,9 @@ export class SearchComponent implements OnInit {
16 name: 'Name', 16 name: 'Name',
17 author: 'Author', 17 author: 'Author',
18 host: 'Pod Host', 18 host: 'Pod Host',
19 magnetUri: 'Magnet URI',
20 tags: 'Tags' 19 tags: 'Tags'
21 } 20 }
22 searchCriterias: Search = { 21 searchCriteria: Search = {
23 field: 'name', 22 field: 'name',
24 value: '' 23 value: ''
25 } 24 }
@@ -30,13 +29,13 @@ export class SearchComponent implements OnInit {
30 // Subscribe if the search changed 29 // Subscribe if the search changed
31 // Usually changed by videos list component 30 // Usually changed by videos list component
32 this.searchService.updateSearch.subscribe( 31 this.searchService.updateSearch.subscribe(
33 newSearchCriterias => { 32 newSearchCriteria => {
34 // Put a field by default 33 // Put a field by default
35 if (!newSearchCriterias.field) { 34 if (!newSearchCriteria.field) {
36 newSearchCriterias.field = 'name' 35 newSearchCriteria.field = 'name'
37 } 36 }
38 37
39 this.searchCriterias = newSearchCriterias 38 this.searchCriteria = newSearchCriteria
40 } 39 }
41 ) 40 )
42 } 41 }
@@ -49,9 +48,9 @@ export class SearchComponent implements OnInit {
49 $event.preventDefault() 48 $event.preventDefault()
50 $event.stopPropagation() 49 $event.stopPropagation()
51 50
52 this.searchCriterias.field = choice 51 this.searchCriteria.field = choice
53 52
54 if (this.searchCriterias.value) { 53 if (this.searchCriteria.value) {
55 this.doSearch() 54 this.doSearch()
56 } 55 }
57 } 56 }
@@ -61,7 +60,7 @@ export class SearchComponent implements OnInit {
61 this.router.navigate([ '/videos/list' ]) 60 this.router.navigate([ '/videos/list' ])
62 } 61 }
63 62
64 this.searchService.searchUpdated.next(this.searchCriterias) 63 this.searchService.searchUpdated.next(this.searchCriteria)
65 } 64 }
66 65
67 getStringChoice (choiceKey: SearchField) { 66 getStringChoice (choiceKey: SearchField) {
diff --git a/client/src/app/videos/+video-edit/video-add.component.html b/client/src/app/videos/+video-edit/video-add.component.html
index a70788ed8..b4e0f9f7c 100644
--- a/client/src/app/videos/+video-edit/video-add.component.html
+++ b/client/src/app/videos/+video-edit/video-add.component.html
@@ -18,6 +18,18 @@
18 </div> 18 </div>
19 19
20 <div class="form-group"> 20 <div class="form-group">
21 <label for="privacy">Privacy</label>
22 <select class="form-control" id="privacy" formControlName="privacy">
23 <option></option>
24 <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
25 </select>
26
27 <div *ngIf="formErrors.privacy" class="alert alert-danger">
28 {{ formErrors.privacy }}
29 </div>
30 </div>
31
32 <div class="form-group">
21 <input 33 <input
22 type="checkbox" id="nsfw" 34 type="checkbox" id="nsfw"
23 formControlName="nsfw" 35 formControlName="nsfw"
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts
index 5b5557ed9..c8094f792 100644
--- a/client/src/app/videos/+video-edit/video-add.component.ts
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -13,7 +13,8 @@ import {
13 VIDEO_DESCRIPTION, 13 VIDEO_DESCRIPTION,
14 VIDEO_TAGS, 14 VIDEO_TAGS,
15 VIDEO_CHANNEL, 15 VIDEO_CHANNEL,
16 VIDEO_FILE 16 VIDEO_FILE,
17 VIDEO_PRIVACY
17} from '../../shared' 18} from '../../shared'
18import { AuthService, ServerService } from '../../core' 19import { AuthService, ServerService } from '../../core'
19import { VideoService } from '../shared' 20import { VideoService } from '../shared'
@@ -34,6 +35,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
34 videoCategories = [] 35 videoCategories = []
35 videoLicences = [] 36 videoLicences = []
36 videoLanguages = [] 37 videoLanguages = []
38 videoPrivacies = []
37 userVideoChannels = [] 39 userVideoChannels = []
38 40
39 tagValidators = VIDEO_TAGS.VALIDATORS 41 tagValidators = VIDEO_TAGS.VALIDATORS
@@ -43,6 +45,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
43 form: FormGroup 45 form: FormGroup
44 formErrors = { 46 formErrors = {
45 name: '', 47 name: '',
48 privacy: '',
46 category: '', 49 category: '',
47 licence: '', 50 licence: '',
48 language: '', 51 language: '',
@@ -52,6 +55,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
52 } 55 }
53 validationMessages = { 56 validationMessages = {
54 name: VIDEO_NAME.MESSAGES, 57 name: VIDEO_NAME.MESSAGES,
58 privacy: VIDEO_PRIVACY.MESSAGES,
55 category: VIDEO_CATEGORY.MESSAGES, 59 category: VIDEO_CATEGORY.MESSAGES,
56 licence: VIDEO_LICENCE.MESSAGES, 60 licence: VIDEO_LICENCE.MESSAGES,
57 language: VIDEO_LANGUAGE.MESSAGES, 61 language: VIDEO_LANGUAGE.MESSAGES,
@@ -79,6 +83,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
79 this.form = this.formBuilder.group({ 83 this.form = this.formBuilder.group({
80 name: [ '', VIDEO_NAME.VALIDATORS ], 84 name: [ '', VIDEO_NAME.VALIDATORS ],
81 nsfw: [ false ], 85 nsfw: [ false ],
86 privacy: [ '', VIDEO_PRIVACY.VALIDATORS ],
82 category: [ '', VIDEO_CATEGORY.VALIDATORS ], 87 category: [ '', VIDEO_CATEGORY.VALIDATORS ],
83 licence: [ '', VIDEO_LICENCE.VALIDATORS ], 88 licence: [ '', VIDEO_LICENCE.VALIDATORS ],
84 language: [ '', VIDEO_LANGUAGE.VALIDATORS ], 89 language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
@@ -95,6 +100,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
95 this.videoCategories = this.serverService.getVideoCategories() 100 this.videoCategories = this.serverService.getVideoCategories()
96 this.videoLicences = this.serverService.getVideoLicences() 101 this.videoLicences = this.serverService.getVideoLicences()
97 this.videoLanguages = this.serverService.getVideoLanguages() 102 this.videoLanguages = this.serverService.getVideoLanguages()
103 this.videoPrivacies = this.serverService.getVideoPrivacies()
98 104
99 this.buildForm() 105 this.buildForm()
100 106
@@ -139,6 +145,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
139 const formValue: VideoCreate = this.form.value 145 const formValue: VideoCreate = this.form.value
140 146
141 const name = formValue.name 147 const name = formValue.name
148 const privacy = formValue.privacy
142 const nsfw = formValue.nsfw 149 const nsfw = formValue.nsfw
143 const category = formValue.category 150 const category = formValue.category
144 const licence = formValue.licence 151 const licence = formValue.licence
@@ -150,6 +157,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
150 157
151 const formData = new FormData() 158 const formData = new FormData()
152 formData.append('name', name) 159 formData.append('name', name)
160 formData.append('privacy', privacy.toString())
153 formData.append('category', '' + category) 161 formData.append('category', '' + category)
154 formData.append('nsfw', '' + nsfw) 162 formData.append('nsfw', '' + nsfw)
155 formData.append('licence', '' + licence) 163 formData.append('licence', '' + licence)
diff --git a/client/src/app/videos/+video-edit/video-update.component.html b/client/src/app/videos/+video-edit/video-update.component.html
index ec040630e..b9c6139b2 100644
--- a/client/src/app/videos/+video-edit/video-update.component.html
+++ b/client/src/app/videos/+video-edit/video-update.component.html
@@ -18,6 +18,18 @@
18 </div> 18 </div>
19 19
20 <div class="form-group"> 20 <div class="form-group">
21 <label for="privacy">Privacy</label>
22 <select class="form-control" id="privacy" formControlName="privacy">
23 <option></option>
24 <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
25 </select>
26
27 <div *ngIf="formErrors.privacy" class="alert alert-danger">
28 {{ formErrors.privacy }}
29 </div>
30 </div>
31
32 <div class="form-group">
21 <input 33 <input
22 type="checkbox" id="nsfw" 34 type="checkbox" id="nsfw"
23 formControlName="nsfw" 35 formControlName="nsfw"
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts
index 6ced77f1a..be663575f 100644
--- a/client/src/app/videos/+video-edit/video-update.component.ts
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -1,7 +1,6 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 2import { FormBuilder, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { Observable } from 'rxjs/Observable'
5import 'rxjs/add/observable/forkJoin' 4import 'rxjs/add/observable/forkJoin'
6 5
7import { NotificationsService } from 'angular2-notifications' 6import { NotificationsService } from 'angular2-notifications'
@@ -14,9 +13,11 @@ import {
14 VIDEO_LICENCE, 13 VIDEO_LICENCE,
15 VIDEO_LANGUAGE, 14 VIDEO_LANGUAGE,
16 VIDEO_DESCRIPTION, 15 VIDEO_DESCRIPTION,
17 VIDEO_TAGS 16 VIDEO_TAGS,
17 VIDEO_PRIVACY
18} from '../../shared' 18} from '../../shared'
19import { VideoEdit, VideoService } from '../shared' 19import { VideoEdit, VideoService } from '../shared'
20import { VideoPrivacy } from '../../../../../shared/models/videos/video-privacy.enum'
20 21
21@Component({ 22@Component({
22 selector: 'my-videos-update', 23 selector: 'my-videos-update',
@@ -29,6 +30,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
29 videoCategories = [] 30 videoCategories = []
30 videoLicences = [] 31 videoLicences = []
31 videoLanguages = [] 32 videoLanguages = []
33 videoPrivacies = []
32 video: VideoEdit 34 video: VideoEdit
33 35
34 tagValidators = VIDEO_TAGS.VALIDATORS 36 tagValidators = VIDEO_TAGS.VALIDATORS
@@ -38,6 +40,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
38 form: FormGroup 40 form: FormGroup
39 formErrors = { 41 formErrors = {
40 name: '', 42 name: '',
43 privacy: '',
41 category: '', 44 category: '',
42 licence: '', 45 licence: '',
43 language: '', 46 language: '',
@@ -45,6 +48,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
45 } 48 }
46 validationMessages = { 49 validationMessages = {
47 name: VIDEO_NAME.MESSAGES, 50 name: VIDEO_NAME.MESSAGES,
51 privacy: VIDEO_PRIVACY.MESSAGES,
48 category: VIDEO_CATEGORY.MESSAGES, 52 category: VIDEO_CATEGORY.MESSAGES,
49 licence: VIDEO_LICENCE.MESSAGES, 53 licence: VIDEO_LICENCE.MESSAGES,
50 language: VIDEO_LANGUAGE.MESSAGES, 54 language: VIDEO_LANGUAGE.MESSAGES,
@@ -67,6 +71,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
67 buildForm () { 71 buildForm () {
68 this.form = this.formBuilder.group({ 72 this.form = this.formBuilder.group({
69 name: [ '', VIDEO_NAME.VALIDATORS ], 73 name: [ '', VIDEO_NAME.VALIDATORS ],
74 privacy: [ '', VIDEO_PRIVACY.VALIDATORS ],
70 nsfw: [ false ], 75 nsfw: [ false ],
71 category: [ '', VIDEO_CATEGORY.VALIDATORS ], 76 category: [ '', VIDEO_CATEGORY.VALIDATORS ],
72 licence: [ '', VIDEO_LICENCE.VALIDATORS ], 77 licence: [ '', VIDEO_LICENCE.VALIDATORS ],
@@ -84,6 +89,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
84 this.videoCategories = this.serverService.getVideoCategories() 89 this.videoCategories = this.serverService.getVideoCategories()
85 this.videoLicences = this.serverService.getVideoLicences() 90 this.videoLicences = this.serverService.getVideoLicences()
86 this.videoLanguages = this.serverService.getVideoLanguages() 91 this.videoLanguages = this.serverService.getVideoLanguages()
92 this.videoPrivacies = this.serverService.getVideoPrivacies()
87 93
88 const uuid: string = this.route.snapshot.params['uuid'] 94 const uuid: string = this.route.snapshot.params['uuid']
89 95
@@ -98,6 +104,16 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
98 video => { 104 video => {
99 this.video = new VideoEdit(video) 105 this.video = new VideoEdit(video)
100 106
107 // We cannot set private a video that was not private anymore
108 if (video.privacy !== VideoPrivacy.PRIVATE) {
109 const newVideoPrivacies = []
110 for (const p of this.videoPrivacies) {
111 if (p.id !== VideoPrivacy.PRIVATE) newVideoPrivacies.push(p)
112 }
113
114 this.videoPrivacies = newVideoPrivacies
115 }
116
101 this.hydrateFormFromVideo() 117 this.hydrateFormFromVideo()
102 }, 118 },
103 119
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 71f986ccd..53648a8d8 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.html
+++ b/client/src/app/videos/+video-watch/video-watch.component.html
@@ -22,7 +22,7 @@
22 <div *ngIf="videoNotFound" id="video-not-found">Video not found :'(</div> 22 <div *ngIf="videoNotFound" id="video-not-found">Video not found :'(</div>
23</div> 23</div>
24 24
25<!-- P2P informations --> 25<!-- P2P information -->
26<div id="torrent-info" class="row"> 26<div id="torrent-info" class="row">
27 <div id="torrent-info-download" class="col-md-4 col-sm-4 col-xs-4">Download: {{ downloadSpeed | bytes }}/s</div> 27 <div id="torrent-info-download" class="col-md-4 col-sm-4 col-xs-4">Download: {{ downloadSpeed | bytes }}/s</div>
28 <div id="torrent-info-upload" class="col-md-4 col-sm-4 col-xs-4">Upload: {{ uploadSpeed | bytes }}/s</div> 28 <div id="torrent-info-upload" class="col-md-4 col-sm-4 col-xs-4">Upload: {{ uploadSpeed | bytes }}/s</div>
@@ -144,6 +144,15 @@
144 <div class="video-details-attributes col-xs-4 col-md-3"> 144 <div class="video-details-attributes col-xs-4 col-md-3">
145 <div class="video-details-attribute"> 145 <div class="video-details-attribute">
146 <span class="video-details-attribute-label"> 146 <span class="video-details-attribute-label">
147 Privacy:
148 </span>
149 <span class="video-details-attribute-value">
150 {{ video.privacyLabel }}
151 </span>
152 </div>
153
154 <div class="video-details-attribute">
155 <span class="video-details-attribute-label">
147 Category: 156 Category:
148 </span> 157 </span>
149 <span class="video-details-attribute-value"> 158 <span class="video-details-attribute-value">
diff --git a/client/src/app/videos/shared/video-details.model.ts b/client/src/app/videos/shared/video-details.model.ts
index 68ded5210..84f96a25f 100644
--- a/client/src/app/videos/shared/video-details.model.ts
+++ b/client/src/app/videos/shared/video-details.model.ts
@@ -5,7 +5,8 @@ import {
5 VideoFile, 5 VideoFile,
6 VideoChannel, 6 VideoChannel,
7 VideoResolution, 7 VideoResolution,
8 UserRight 8 UserRight,
9 VideoPrivacy
9} from '../../../../../shared' 10} from '../../../../../shared'
10 11
11export class VideoDetails extends Video implements VideoDetailsServerModel { 12export class VideoDetails extends Video implements VideoDetailsServerModel {
@@ -41,10 +42,14 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
41 descriptionPath: string 42 descriptionPath: string
42 files: VideoFile[] 43 files: VideoFile[]
43 channel: VideoChannel 44 channel: VideoChannel
45 privacy: VideoPrivacy
46 privacyLabel: string
44 47
45 constructor (hash: VideoDetailsServerModel) { 48 constructor (hash: VideoDetailsServerModel) {
46 super(hash) 49 super(hash)
47 50
51 this.privacy = hash.privacy
52 this.privacyLabel = hash.privacyLabel
48 this.descriptionPath = hash.descriptionPath 53 this.descriptionPath = hash.descriptionPath
49 this.files = hash.files 54 this.files = hash.files
50 this.channel = hash.channel 55 this.channel = hash.channel
diff --git a/client/src/app/videos/shared/video-edit.model.ts b/client/src/app/videos/shared/video-edit.model.ts
index e0b7bf130..88d23a59f 100644
--- a/client/src/app/videos/shared/video-edit.model.ts
+++ b/client/src/app/videos/shared/video-edit.model.ts
@@ -1,4 +1,5 @@
1import { VideoDetails } from './video-details.model' 1import { VideoDetails } from './video-details.model'
2import { VideoPrivacy } from '../../../../../shared/models/videos/video-privacy.enum'
2 3
3export class VideoEdit { 4export class VideoEdit {
4 category: number 5 category: number
@@ -9,6 +10,7 @@ export class VideoEdit {
9 tags: string[] 10 tags: string[]
10 nsfw: boolean 11 nsfw: boolean
11 channel: number 12 channel: number
13 privacy: VideoPrivacy
12 uuid?: string 14 uuid?: string
13 id?: number 15 id?: number
14 16
@@ -23,6 +25,7 @@ export class VideoEdit {
23 this.tags = videoDetails.tags 25 this.tags = videoDetails.tags
24 this.nsfw = videoDetails.nsfw 26 this.nsfw = videoDetails.nsfw
25 this.channel = videoDetails.channel.id 27 this.channel = videoDetails.channel.id
28 this.privacy = videoDetails.privacy
26 } 29 }
27 30
28 patch (values: Object) { 31 patch (values: Object) {
@@ -40,7 +43,8 @@ export class VideoEdit {
40 name: this.name, 43 name: this.name,
41 tags: this.tags, 44 tags: this.tags,
42 nsfw: this.nsfw, 45 nsfw: this.nsfw,
43 channel: this.channel 46 channel: this.channel,
47 privacy: this.privacy
44 } 48 }
45 } 49 }
46} 50}
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
index 7d5372334..8459aa0d3 100644
--- a/client/src/app/videos/shared/video.service.ts
+++ b/client/src/app/videos/shared/video.service.ts
@@ -19,7 +19,6 @@ import {
19 UserVideoRate, 19 UserVideoRate,
20 VideoRateType, 20 VideoRateType,
21 VideoUpdate, 21 VideoUpdate,
22 VideoAbuseCreate,
23 UserVideoRateUpdate, 22 UserVideoRateUpdate,
24 Video as VideoServerModel, 23 Video as VideoServerModel,
25 VideoDetails as VideoDetailsServerModel, 24 VideoDetails as VideoDetailsServerModel,
@@ -51,6 +50,7 @@ export class VideoService {
51 licence: video.licence, 50 licence: video.licence,
52 language, 51 language,
53 description: video.description, 52 description: video.description,
53 privacy: video.privacy,
54 tags: video.tags, 54 tags: video.tags,
55 nsfw: video.nsfw 55 nsfw: video.nsfw
56 } 56 }
@@ -63,22 +63,35 @@ export class VideoService {
63 uploadVideo (video: FormData) { 63 uploadVideo (video: FormData) {
64 const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true }) 64 const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
65 65
66 return this.authHttp.request(req) 66 return this.authHttp
67 .catch(this.restExtractor.handleError) 67 .request(req)
68 .catch(this.restExtractor.handleError)
68 } 69 }
69 70
70 getVideos (videoPagination: VideoPagination, sort: SortField) { 71 getMyVideos (videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
71 const pagination = this.videoPaginationToRestPagination(videoPagination) 72 const pagination = this.videoPaginationToRestPagination(videoPagination)
72 73
73 let params = new HttpParams() 74 let params = new HttpParams()
74 params = this.restService.addRestGetParams(params, pagination, sort) 75 params = this.restService.addRestGetParams(params, pagination, sort)
75 76
76 return this.authHttp.get(VideoService.BASE_VIDEO_URL, { params }) 77 return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params })
77 .map(this.extractVideos) 78 .map(this.extractVideos)
78 .catch((res) => this.restExtractor.handleError(res)) 79 .catch((res) => this.restExtractor.handleError(res))
79 } 80 }
80 81
81 searchVideos (search: Search, videoPagination: VideoPagination, sort: SortField) { 82 getVideos (videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
83 const pagination = this.videoPaginationToRestPagination(videoPagination)
84
85 let params = new HttpParams()
86 params = this.restService.addRestGetParams(params, pagination, sort)
87
88 return this.authHttp
89 .get(VideoService.BASE_VIDEO_URL, { params })
90 .map(this.extractVideos)
91 .catch((res) => this.restExtractor.handleError(res))
92 }
93
94 searchVideos (search: Search, videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
82 const url = VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value) 95 const url = VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value)
83 96
84 const pagination = this.videoPaginationToRestPagination(videoPagination) 97 const pagination = this.videoPaginationToRestPagination(videoPagination)
@@ -88,15 +101,17 @@ export class VideoService {
88 101
89 if (search.field) params.set('field', search.field) 102 if (search.field) params.set('field', search.field)
90 103
91 return this.authHttp.get<ResultList<VideoServerModel>>(url, { params }) 104 return this.authHttp
92 .map(this.extractVideos) 105 .get<ResultList<VideoServerModel>>(url, { params })
93 .catch((res) => this.restExtractor.handleError(res)) 106 .map(this.extractVideos)
107 .catch((res) => this.restExtractor.handleError(res))
94 } 108 }
95 109
96 removeVideo (id: number) { 110 removeVideo (id: number) {
97 return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) 111 return this.authHttp
98 .map(this.restExtractor.extractDataBool) 112 .delete(VideoService.BASE_VIDEO_URL + id)
99 .catch((res) => this.restExtractor.handleError(res)) 113 .map(this.restExtractor.extractDataBool)
114 .catch((res) => this.restExtractor.handleError(res))
100 } 115 }
101 116
102 loadCompleteDescription (descriptionPath: string) { 117 loadCompleteDescription (descriptionPath: string) {
@@ -117,8 +132,9 @@ export class VideoService {
117 getUserVideoRating (id: number): Observable<UserVideoRate> { 132 getUserVideoRating (id: number): Observable<UserVideoRate> {
118 const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating' 133 const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating'
119 134
120 return this.authHttp.get(url) 135 return this.authHttp
121 .catch(res => this.restExtractor.handleError(res)) 136 .get(url)
137 .catch(res => this.restExtractor.handleError(res))
122 } 138 }
123 139
124 private videoPaginationToRestPagination (videoPagination: VideoPagination) { 140 private videoPaginationToRestPagination (videoPagination: VideoPagination) {
@@ -134,9 +150,10 @@ export class VideoService {
134 rating: rateType 150 rating: rateType
135 } 151 }
136 152
137 return this.authHttp.put(url, body) 153 return this.authHttp
138 .map(this.restExtractor.extractDataBool) 154 .put(url, body)
139 .catch(res => this.restExtractor.handleError(res)) 155 .map(this.restExtractor.extractDataBool)
156 .catch(res => this.restExtractor.handleError(res))
140 } 157 }
141 158
142 private extractVideos (result: ResultList<VideoServerModel>) { 159 private extractVideos (result: ResultList<VideoServerModel>) {
diff --git a/client/src/app/videos/video-list/index.ts b/client/src/app/videos/video-list/index.ts
index a490e6bb5..ed2bb1657 100644
--- a/client/src/app/videos/video-list/index.ts
+++ b/client/src/app/videos/video-list/index.ts
@@ -1,4 +1,3 @@
1export * from './loader.component' 1export * from './my-videos.component'
2export * from './video-list.component' 2export * from './video-list.component'
3export * from './video-miniature.component' 3export * from './shared'
4export * from './video-sort.component'
diff --git a/client/src/app/videos/video-list/my-videos.component.ts b/client/src/app/videos/video-list/my-videos.component.ts
new file mode 100644
index 000000000..648741a40
--- /dev/null
+++ b/client/src/app/videos/video-list/my-videos.component.ts
@@ -0,0 +1,36 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3
4import { NotificationsService } from 'angular2-notifications'
5
6import { AbstractVideoList } from './shared'
7import { VideoService } from '../shared'
8
9@Component({
10 selector: 'my-videos',
11 styleUrls: [ './shared/abstract-video-list.scss' ],
12 templateUrl: './shared/abstract-video-list.html'
13})
14export class MyVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
15
16 constructor (
17 protected router: Router,
18 protected route: ActivatedRoute,
19 protected notificationsService: NotificationsService,
20 private videoService: VideoService
21 ) {
22 super()
23 }
24
25 ngOnInit () {
26 super.ngOnInit()
27 }
28
29 ngOnDestroy () {
30 this.subActivatedRoute.unsubscribe()
31 }
32
33 getVideosObservable () {
34 return this.videoService.getMyVideos(this.pagination, this.sort)
35 }
36}
diff --git a/client/src/app/videos/video-list/video-list.component.html b/client/src/app/videos/video-list/shared/abstract-video-list.html
index 680fba3f5..680fba3f5 100644
--- a/client/src/app/videos/video-list/video-list.component.html
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.html
diff --git a/client/src/app/videos/video-list/video-list.component.scss b/client/src/app/videos/video-list/shared/abstract-video-list.scss
index 4b4409602..4b4409602 100644
--- a/client/src/app/videos/video-list/video-list.component.scss
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.scss
diff --git a/client/src/app/videos/video-list/shared/abstract-video-list.ts b/client/src/app/videos/video-list/shared/abstract-video-list.ts
new file mode 100644
index 000000000..87d5bc48a
--- /dev/null
+++ b/client/src/app/videos/video-list/shared/abstract-video-list.ts
@@ -0,0 +1,104 @@
1import { OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { Subscription } from 'rxjs/Subscription'
4import { BehaviorSubject } from 'rxjs/BehaviorSubject'
5import { Observable } from 'rxjs/Observable'
6
7import { NotificationsService } from 'angular2-notifications'
8
9import {
10 SortField,
11 Video,
12 VideoPagination
13} from '../../shared'
14
15export abstract class AbstractVideoList implements OnInit, OnDestroy {
16 loading: BehaviorSubject<boolean> = new BehaviorSubject(false)
17 pagination: VideoPagination = {
18 currentPage: 1,
19 itemsPerPage: 25,
20 totalItems: null
21 }
22 sort: SortField
23 videos: Video[] = []
24
25 protected notificationsService: NotificationsService
26 protected router: Router
27 protected route: ActivatedRoute
28
29 protected subActivatedRoute: Subscription
30
31 abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
32
33 ngOnInit () {
34 // Subscribe to route changes
35 this.subActivatedRoute = this.route.params.subscribe(routeParams => {
36 this.loadRouteParams(routeParams)
37
38 this.getVideos()
39 })
40 }
41
42 ngOnDestroy () {
43 this.subActivatedRoute.unsubscribe()
44 }
45
46 getVideos () {
47 this.loading.next(true)
48 this.videos = []
49
50 const observable = this.getVideosObservable()
51
52 observable.subscribe(
53 ({ videos, totalVideos }) => {
54 this.videos = videos
55 this.pagination.totalItems = totalVideos
56
57 this.loading.next(false)
58 },
59 error => this.notificationsService.error('Error', error.text)
60 )
61 }
62
63 isThereNoVideo () {
64 return !this.loading.getValue() && this.videos.length === 0
65 }
66
67 onPageChanged (event: { page: number }) {
68 // Be sure the current page is set
69 this.pagination.currentPage = event.page
70
71 this.navigateToNewParams()
72 }
73
74 onSort (sort: SortField) {
75 this.sort = sort
76
77 this.navigateToNewParams()
78 }
79
80 protected buildRouteParams () {
81 // There is always a sort and a current page
82 const params = {
83 sort: this.sort,
84 page: this.pagination.currentPage
85 }
86
87 return params
88 }
89
90 protected loadRouteParams (routeParams: { [ key: string ]: any }) {
91 this.sort = routeParams['sort'] as SortField || '-createdAt'
92
93 if (routeParams['page'] !== undefined) {
94 this.pagination.currentPage = parseInt(routeParams['page'], 10)
95 } else {
96 this.pagination.currentPage = 1
97 }
98 }
99
100 protected navigateToNewParams () {
101 const routeParams = this.buildRouteParams()
102 this.router.navigate([ '/videos/list', routeParams ])
103 }
104}
diff --git a/client/src/app/videos/video-list/shared/index.ts b/client/src/app/videos/video-list/shared/index.ts
new file mode 100644
index 000000000..2c9804e6d
--- /dev/null
+++ b/client/src/app/videos/video-list/shared/index.ts
@@ -0,0 +1,4 @@
1export * from './abstract-video-list'
2export * from './loader.component'
3export * from './video-miniature.component'
4export * from './video-sort.component'
diff --git a/client/src/app/videos/video-list/loader.component.html b/client/src/app/videos/video-list/shared/loader.component.html
index 38d06950e..38d06950e 100644
--- a/client/src/app/videos/video-list/loader.component.html
+++ b/client/src/app/videos/video-list/shared/loader.component.html
diff --git a/client/src/app/videos/video-list/loader.component.ts b/client/src/app/videos/video-list/shared/loader.component.ts
index f37d70c85..f37d70c85 100644
--- a/client/src/app/videos/video-list/loader.component.ts
+++ b/client/src/app/videos/video-list/shared/loader.component.ts
diff --git a/client/src/app/videos/video-list/video-miniature.component.html b/client/src/app/videos/video-list/shared/video-miniature.component.html
index abe87025f..abe87025f 100644
--- a/client/src/app/videos/video-list/video-miniature.component.html
+++ b/client/src/app/videos/video-list/shared/video-miniature.component.html
diff --git a/client/src/app/videos/video-list/video-miniature.component.scss b/client/src/app/videos/video-list/shared/video-miniature.component.scss
index 066792d10..066792d10 100644
--- a/client/src/app/videos/video-list/video-miniature.component.scss
+++ b/client/src/app/videos/video-list/shared/video-miniature.component.scss
diff --git a/client/src/app/videos/video-list/video-miniature.component.ts b/client/src/app/videos/video-list/shared/video-miniature.component.ts
index 18434dad2..e5a87907b 100644
--- a/client/src/app/videos/video-list/video-miniature.component.ts
+++ b/client/src/app/videos/video-list/shared/video-miniature.component.ts
@@ -1,7 +1,7 @@
1import { Component, Input } from '@angular/core' 1import { Component, Input } from '@angular/core'
2 2
3import { SortField, Video } from '../shared' 3import { SortField, Video } from '../../shared'
4import { User } from '../../shared' 4import { User } from '../../../shared'
5 5
6@Component({ 6@Component({
7 selector: 'my-video-miniature', 7 selector: 'my-video-miniature',
diff --git a/client/src/app/videos/video-list/video-sort.component.html b/client/src/app/videos/video-list/shared/video-sort.component.html
index 3bece0b22..3bece0b22 100644
--- a/client/src/app/videos/video-list/video-sort.component.html
+++ b/client/src/app/videos/video-list/shared/video-sort.component.html
diff --git a/client/src/app/videos/video-list/video-sort.component.ts b/client/src/app/videos/video-list/shared/video-sort.component.ts
index 64916bf16..8aa89d32b 100644
--- a/client/src/app/videos/video-list/video-sort.component.ts
+++ b/client/src/app/videos/video-list/shared/video-sort.component.ts
@@ -1,6 +1,6 @@
1import { Component, EventEmitter, Input, Output } from '@angular/core' 1import { Component, EventEmitter, Input, Output } from '@angular/core'
2 2
3import { SortField } from '../shared' 3import { SortField } from '../../shared'
4 4
5@Component({ 5@Component({
6 selector: 'my-video-sort', 6 selector: 'my-video-sort',
diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts
index bf6f60215..784162679 100644
--- a/client/src/app/videos/video-list/video-list.component.ts
+++ b/client/src/app/videos/video-list/video-list.component.ts
@@ -1,51 +1,33 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { Subscription } from 'rxjs/Subscription' 3import { Subscription } from 'rxjs/Subscription'
4import { BehaviorSubject } from 'rxjs/BehaviorSubject'
5 4
6import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
7 6
8import { AuthService } from '../../core' 7import { VideoService } from '../shared'
9import { 8import { Search, SearchField, SearchService } from '../../shared'
10 SortField, 9import { AbstractVideoList } from './shared'
11 Video,
12 VideoService,
13 VideoPagination
14} from '../shared'
15import { Search, SearchField, SearchService, User } from '../../shared'
16 10
17@Component({ 11@Component({
18 selector: 'my-videos-list', 12 selector: 'my-videos-list',
19 styleUrls: [ './video-list.component.scss' ], 13 styleUrls: [ './shared/abstract-video-list.scss' ],
20 templateUrl: './video-list.component.html' 14 templateUrl: './shared/abstract-video-list.html'
21}) 15})
22export class VideoListComponent implements OnInit, OnDestroy { 16export class VideoListComponent extends AbstractVideoList implements OnInit, OnDestroy {
23 loading: BehaviorSubject<boolean> = new BehaviorSubject(false)
24 pagination: VideoPagination = {
25 currentPage: 1,
26 itemsPerPage: 25,
27 totalItems: null
28 }
29 sort: SortField
30 user: User
31 videos: Video[] = []
32
33 private search: Search 17 private search: Search
34 private subActivatedRoute: Subscription
35 private subSearch: Subscription 18 private subSearch: Subscription
36 19
37 constructor ( 20 constructor (
38 private authService: AuthService, 21 protected router: Router,
39 private notificationsService: NotificationsService, 22 protected route: ActivatedRoute,
40 private router: Router, 23 protected notificationsService: NotificationsService,
41 private route: ActivatedRoute,
42 private videoService: VideoService, 24 private videoService: VideoService,
43 private searchService: SearchService 25 private searchService: SearchService
44 ) {} 26 ) {
27 super()
28 }
45 29
46 ngOnInit () { 30 ngOnInit () {
47 this.user = this.authService.getUser()
48
49 // Subscribe to route changes 31 // Subscribe to route changes
50 this.subActivatedRoute = this.route.params.subscribe(routeParams => { 32 this.subActivatedRoute = this.route.params.subscribe(routeParams => {
51 this.loadRouteParams(routeParams) 33 this.loadRouteParams(routeParams)
@@ -66,14 +48,12 @@ export class VideoListComponent implements OnInit, OnDestroy {
66 } 48 }
67 49
68 ngOnDestroy () { 50 ngOnDestroy () {
69 this.subActivatedRoute.unsubscribe() 51 super.ngOnDestroy()
52
70 this.subSearch.unsubscribe() 53 this.subSearch.unsubscribe()
71 } 54 }
72 55
73 getVideos () { 56 getVideosObservable () {
74 this.loading.next(true)
75 this.videos = []
76
77 let observable = null 57 let observable = null
78 if (this.search.value) { 58 if (this.search.value) {
79 observable = this.videoService.searchVideos(this.search, this.pagination, this.sort) 59 observable = this.videoService.searchVideos(this.search, this.pagination, this.sort)
@@ -81,40 +61,11 @@ export class VideoListComponent implements OnInit, OnDestroy {
81 observable = this.videoService.getVideos(this.pagination, this.sort) 61 observable = this.videoService.getVideos(this.pagination, this.sort)
82 } 62 }
83 63
84 observable.subscribe( 64 return observable
85 ({ videos, totalVideos }) => {
86 this.videos = videos
87 this.pagination.totalItems = totalVideos
88
89 this.loading.next(false)
90 },
91 error => this.notificationsService.error('Error', error.text)
92 )
93 }
94
95 isThereNoVideo () {
96 return !this.loading.getValue() && this.videos.length === 0
97 }
98
99 onPageChanged (event: { page: number }) {
100 // Be sure the current page is set
101 this.pagination.currentPage = event.page
102
103 this.navigateToNewParams()
104 } 65 }
105 66
106 onSort (sort: SortField) { 67 protected buildRouteParams () {
107 this.sort = sort 68 const params = super.buildRouteParams()
108
109 this.navigateToNewParams()
110 }
111
112 private buildRouteParams () {
113 // There is always a sort and a current page
114 const params = {
115 sort: this.sort,
116 page: this.pagination.currentPage
117 }
118 69
119 // Maybe there is a search 70 // Maybe there is a search
120 if (this.search.value) { 71 if (this.search.value) {
@@ -125,7 +76,9 @@ export class VideoListComponent implements OnInit, OnDestroy {
125 return params 76 return params
126 } 77 }
127 78
128 private loadRouteParams (routeParams: { [ key: string ]: any }) { 79 protected loadRouteParams (routeParams: { [ key: string ]: any }) {
80 super.loadRouteParams(routeParams)
81
129 if (routeParams['search'] !== undefined) { 82 if (routeParams['search'] !== undefined) {
130 this.search = { 83 this.search = {
131 value: routeParams['search'], 84 value: routeParams['search'],
@@ -137,18 +90,5 @@ export class VideoListComponent implements OnInit, OnDestroy {
137 field: 'name' 90 field: 'name'
138 } 91 }
139 } 92 }
140
141 this.sort = routeParams['sort'] as SortField || '-createdAt'
142
143 if (routeParams['page'] !== undefined) {
144 this.pagination.currentPage = parseInt(routeParams['page'], 10)
145 } else {
146 this.pagination.currentPage = 1
147 }
148 }
149
150 private navigateToNewParams () {
151 const routeParams = this.buildRouteParams()
152 this.router.navigate([ '/videos/list', routeParams ])
153 } 93 }
154} 94}
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts
index d3869748b..3ca3e5486 100644
--- a/client/src/app/videos/videos-routing.module.ts
+++ b/client/src/app/videos/videos-routing.module.ts
@@ -3,7 +3,7 @@ import { RouterModule, Routes } from '@angular/router'
3 3
4import { MetaGuard } from '@ngx-meta/core' 4import { MetaGuard } from '@ngx-meta/core'
5 5
6import { VideoListComponent } from './video-list' 6import { VideoListComponent, MyVideosComponent } from './video-list'
7import { VideosComponent } from './videos.component' 7import { VideosComponent } from './videos.component'
8 8
9const videosRoutes: Routes = [ 9const videosRoutes: Routes = [
@@ -13,6 +13,15 @@ const videosRoutes: Routes = [
13 canActivateChild: [ MetaGuard ], 13 canActivateChild: [ MetaGuard ],
14 children: [ 14 children: [
15 { 15 {
16 path: 'mine',
17 component: MyVideosComponent,
18 data: {
19 meta: {
20 title: 'My videos'
21 }
22 }
23 },
24 {
16 path: 'list', 25 path: 'list',
17 component: VideoListComponent, 26 component: VideoListComponent,
18 data: { 27 data: {
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts
index 3a0c3feac..ecc351b65 100644
--- a/client/src/app/videos/videos.module.ts
+++ b/client/src/app/videos/videos.module.ts
@@ -2,7 +2,13 @@ import { NgModule } from '@angular/core'
2 2
3import { VideosRoutingModule } from './videos-routing.module' 3import { VideosRoutingModule } from './videos-routing.module'
4import { VideosComponent } from './videos.component' 4import { VideosComponent } from './videos.component'
5import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list' 5import {
6 LoaderComponent,
7 VideoListComponent,
8 MyVideosComponent,
9 VideoMiniatureComponent,
10 VideoSortComponent
11} from './video-list'
6import { VideoService } from './shared' 12import { VideoService } from './shared'
7import { SharedModule } from '../shared' 13import { SharedModule } from '../shared'
8 14
@@ -16,6 +22,7 @@ import { SharedModule } from '../shared'
16 VideosComponent, 22 VideosComponent,
17 23
18 VideoListComponent, 24 VideoListComponent,
25 MyVideosComponent,
19 VideoMiniatureComponent, 26 VideoMiniatureComponent,
20 VideoSortComponent, 27 VideoSortComponent,
21 28
diff --git a/client/src/sass/video-js-custom.scss b/client/src/sass/video-js-custom.scss
index c5f668f17..6ad21988e 100644
--- a/client/src/sass/video-js-custom.scss
+++ b/client/src/sass/video-js-custom.scss
@@ -334,71 +334,34 @@ $slider-bg-color: lighten($primary-background-color, 33%);
334 334
335// Thanks: https://projects.lukehaas.me/css-loaders/ 335// Thanks: https://projects.lukehaas.me/css-loaders/
336.vjs-loading-spinner { 336.vjs-loading-spinner {
337 border: none; 337 margin: -25px 0 0 -25px;
338 opacity: 1; 338 position: absolute;
339 top: 50%;
340 left: 50%;
339 font-size: 10px; 341 font-size: 10px;
340 text-indent: -9999em;
341 width: 5em;
342 height: 5em;
343 border-radius: 50%;
344 background: #ffffff;
345 background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
346 background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
347 background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
348 background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
349 background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
350 position: relative; 342 position: relative;
351 -webkit-animation: load3 1.4s infinite linear; 343 text-indent: -9999em;
352 animation: load3 1.4s infinite linear; 344 border: 0.7em solid rgba(255, 255, 255, 0.2);
353 -webkit-transform: translateZ(0); 345 border-left-color: #ffffff;
354 -ms-transform: translateZ(0);
355 transform: translateZ(0); 346 transform: translateZ(0);
347 animation: spinner 1.4s infinite linear;
356 348
357 &:before { 349 &:before {
358 width: 50%;
359 height: 50%;
360 background: #ffffff;
361 border-radius: 100% 0 0 0;
362 position: absolute;
363 top: 0;
364 left: 0;
365 content: '';
366 animation: none !important; 350 animation: none !important;
367 margin: 0 !important;
368 } 351 }
369 352
370 &:after { 353 &:after {
371 background: #000;
372 width: 75%;
373 height: 75%;
374 border-radius: 50%; 354 border-radius: 50%;
375 content: ''; 355 width: 6em;
376 margin: auto; 356 height: 6em;
377 position: absolute;
378 top: 0;
379 left: 0;
380 bottom: 0;
381 right: 0;
382 animation: none !important; 357 animation: none !important;
383 } 358 }
384 359
385 @-webkit-keyframes load3 { 360 @keyframes spinner {
386 0% {
387 -webkit-transform: rotate(0deg);
388 transform: rotate(0deg);
389 }
390 100% {
391 -webkit-transform: rotate(360deg);
392 transform: rotate(360deg);
393 }
394 }
395 @keyframes load3 {
396 0% { 361 0% {
397 -webkit-transform: rotate(0deg);
398 transform: rotate(0deg); 362 transform: rotate(0deg);
399 } 363 }
400 100% { 364 100% {
401 -webkit-transform: rotate(360deg);
402 transform: rotate(360deg); 365 transform: rotate(360deg);
403 } 366 }
404 } 367 }