From 00a446454d4721fc49517815655f6b4f8a17b554 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 10 Jun 2016 17:43:40 +0200 Subject: [PATCH] Add tags support to the video list --- client/src/app/app.component.html | 24 +++++------ client/src/app/app.component.scss | 4 +- client/src/app/app.component.ts | 19 ++++----- client/src/app/login/login.component.ts | 4 +- client/src/app/shared/search/index.ts | 1 + .../src/app/shared/search/search.component.ts | 21 +++++++++- .../src/app/shared/search/search.service.ts | 15 +++++++ client/src/app/videos/shared/video.model.ts | 3 ++ .../videos/video-add/video-add.component.html | 4 +- .../videos/video-add/video-add.component.ts | 2 +- .../videos/video-list/video-list.component.ts | 36 +++++++++------- .../video-list/video-miniature.component.html | 14 ++++--- .../video-list/video-miniature.component.scss | 42 ++++++++++++++++--- .../video-list/video-miniature.component.ts | 2 +- .../video-watch/video-watch.component.ts | 10 ++--- client/src/vendor.ts | 2 +- client/tsconfig.json | 1 + 17 files changed, 140 insertions(+), 64 deletions(-) create mode 100644 client/src/app/shared/search/search.service.ts diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 48e97d523..7e2a0c5f6 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -14,40 +14,40 @@
- -
+
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index e02c2d5b0..1a9a196ff 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss @@ -8,7 +8,7 @@ menu { margin-right: 20px; border-right: 1px solid rgba(0, 0, 0, 0.2); - .panel_button { + .panel-button { margin: 8px; cursor: pointer; transition: margin 0.2s; @@ -27,6 +27,6 @@ menu { } } -.panel_block:not(:last-child) { +.panel-block:not(:last-child) { border-bottom: 1px solid rgba(0, 0, 0, 0.1); } diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 81b700a21..2a1486fb2 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { HTTP_PROVIDERS } from '@angular/http'; -import { RouteConfig, Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated'; +import { Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, Routes } from '@angular/router'; import { FriendService } from './friends'; import { LoginComponent } from './login'; @@ -16,27 +16,23 @@ import { VideoWatchComponent, VideoService } from './videos'; +import { SearchService } from './shared'; // Temporary -@RouteConfig([ +@Routes([ { path: '/users/login', - name: 'UserLogin', component: LoginComponent }, { path: '/videos/list', - name: 'VideosList', - component: VideoListComponent, - useAsDefault: true + component: VideoListComponent }, { path: '/videos/watch/:id', - name: 'VideosWatch', component: VideoWatchComponent }, { path: '/videos/add', - name: 'VideosAdd', component: VideoAddComponent } ]) @@ -46,7 +42,7 @@ import { template: require('./app.component.html'), styles: [ require('./app.component.scss') ], directives: [ ROUTER_DIRECTIVES, SearchComponent ], - providers: [ AuthService, FriendService, HTTP_PROVIDERS, ROUTER_PROVIDERS, VideoService ] + providers: [ AuthService, FriendService, HTTP_PROVIDERS, ROUTER_PROVIDERS, VideoService, SearchService ] }) export class AppComponent { @@ -75,12 +71,13 @@ export class AppComponent { field: search.field, search: search.value }; - this.router.navigate(['VideosList', params]); + this.router.navigate(['/videos/list', params]); } else { - this.router.navigate(['VideosList']); + this.router.navigate(['/videos/list']); } } + // FIXME logout() { // this._authService.logout(); } diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts index 768594ac4..bcfa021fa 100644 --- a/client/src/app/login/login.component.ts +++ b/client/src/app/login/login.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { Router } from '@angular/router-deprecated'; +import { Router } from '@angular/router'; import { AuthService, AuthStatus, User } from '../shared'; @@ -26,7 +26,7 @@ export class LoginComponent { this.authService.setStatus(AuthStatus.LoggedIn); - this.router.navigate(['VideosList']); + this.router.navigate(['/videos/list']); }, error => { if (error.error === 'invalid_grant') { diff --git a/client/src/app/shared/search/index.ts b/client/src/app/shared/search/index.ts index a49a4f1a9..a897ed099 100644 --- a/client/src/app/shared/search/index.ts +++ b/client/src/app/shared/search/index.ts @@ -1,3 +1,4 @@ export * from './search-field.type'; export * from './search.component'; export * from './search.model'; +export * from './search.service'; diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts index c14c2d99c..ed1ce807a 100644 --- a/client/src/app/shared/search/search.component.ts +++ b/client/src/app/shared/search/search.component.ts @@ -1,9 +1,10 @@ -import { Component, EventEmitter, Output } from '@angular/core'; +import { Component, EventEmitter, Output, OnInit } from '@angular/core'; import { DROPDOWN_DIRECTIVES} from 'ng2-bootstrap/components/dropdown'; import { Search } from './search.model'; import { SearchField } from './search-field.type'; +import { SearchService } from './search.service'; // Temporary @Component({ selector: 'my-search', @@ -11,7 +12,7 @@ import { SearchField } from './search-field.type'; directives: [ DROPDOWN_DIRECTIVES ] }) -export class SearchComponent { +export class SearchComponent implements OnInit { @Output() search = new EventEmitter(); fieldChoices = { @@ -26,6 +27,21 @@ export class SearchComponent { value: '' }; + constructor(private searchService: SearchService) {} + + ngOnInit() { + this.searchService.searchChanged.subscribe( + newSearchCriterias => { + // Put a field by default + if (!newSearchCriterias.field) { + newSearchCriterias.field = 'name'; + } + + this.searchCriterias = newSearchCriterias; + } + ); + } + get choiceKeys() { return Object.keys(this.fieldChoices); } @@ -35,6 +51,7 @@ export class SearchComponent { $event.stopPropagation(); this.searchCriterias.field = choice; + this.doSearch(); } doSearch() { diff --git a/client/src/app/shared/search/search.service.ts b/client/src/app/shared/search/search.service.ts new file mode 100644 index 000000000..787c02d2b --- /dev/null +++ b/client/src/app/shared/search/search.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +import { Search } from './search.model'; + +// This class is needed to communicate between videos/list and search component +// Remove it when we'll be able to subscribe to router changes +@Injectable() +export class SearchService { + searchChanged: Subject; + + constructor() { + this.searchChanged = new Subject(); + } +} diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts index 614403d79..65417f751 100644 --- a/client/src/app/videos/shared/video.model.ts +++ b/client/src/app/videos/shared/video.model.ts @@ -9,6 +9,7 @@ export class Video { magnetUri: string; name: string; podUrl: string; + tags: string[]; thumbnailPath: string; private static createByString(author: string, podUrl: string) { @@ -42,6 +43,7 @@ export class Video { magnetUri: string, name: string, podUrl: string, + tags: string[], thumbnailPath: string }) { this.author = hash.author; @@ -53,6 +55,7 @@ export class Video { this.magnetUri = hash.magnetUri; this.name = hash.name; this.podUrl = hash.podUrl; + this.tags = hash.tags; this.thumbnailPath = hash.thumbnailPath; this.by = Video.createByString(hash.author, hash.podUrl); diff --git a/client/src/app/videos/video-add/video-add.component.html b/client/src/app/videos/video-add/video-add.component.html index 6b2eb9377..bcd78c7cb 100644 --- a/client/src/app/videos/video-add/video-add.component.html +++ b/client/src/app/videos/video-add/video-add.component.html @@ -21,12 +21,12 @@ ngControl="tags" #tags="ngForm" [disabled]="isTagsInputDisabled" (keyup)="onTagKeyPress($event)" [(ngModel)]="currentTag" >
- A tag should be between 2 and 10 characters long + A tag should be between 2 and 10 characters (alphanumeric) long
-
+
{{ tag }} x
diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-add/video-add.component.ts index 2b45ea125..7d8fbdc29 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-add/video-add.component.ts @@ -1,6 +1,6 @@ import { Control, ControlGroup, Validators } from '@angular/common'; import { Component, ElementRef, OnInit } from '@angular/core'; -import { Router } from '@angular/router-deprecated'; +import { Router } from '@angular/router'; import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; import { PROGRESSBAR_DIRECTIVES } from 'ng2-bootstrap/components/progressbar'; 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 059317383..46263eb65 100644 --- a/client/src/app/videos/video-list/video-list.component.ts +++ b/client/src/app/videos/video-list/video-list.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { Router, ROUTER_DIRECTIVES, RouteParams } from '@angular/router-deprecated'; +import { Router, ROUTER_DIRECTIVES, RouteSegment } from '@angular/router'; import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination'; @@ -13,6 +13,7 @@ import { import { AuthService, Search, SearchField, User } from '../../shared'; import { VideoMiniatureComponent } from './video-miniature.component'; import { VideoSortComponent } from './video-sort.component'; +import { SearchService } from '../../shared'; @Component({ selector: 'my-videos-list', @@ -37,22 +38,26 @@ export class VideoListComponent implements OnInit { constructor( private authService: AuthService, private router: Router, - private routeParams: RouteParams, - private videoService: VideoService - ) { - this.search = { - value: this.routeParams.get('search'), - field: this.routeParams.get('field') - }; - - this.sort = this.routeParams.get('sort') || '-createdDate'; - } + private routeSegment: RouteSegment, + private videoService: VideoService, + private searchService: SearchService // Temporary + ) {} ngOnInit() { if (this.authService.isLoggedIn()) { this.user = User.load(); } + this.search = { + value: this.routeSegment.getParam('search'), + field: this.routeSegment.getParam('field') + }; + + // Temporary + this.searchChanged(this.search); + + this.sort = this.routeSegment.getParam('sort') || '-createdDate'; + this.getVideos(); } @@ -62,7 +67,7 @@ export class VideoListComponent implements OnInit { let observable = null; - if (this.search.value !== null) { + if (this.search.value) { observable = this.videoService.searchVideos(this.search, this.pagination, this.sort); } else { observable = this.videoService.getVideos(this.pagination, this.sort); @@ -99,7 +104,10 @@ export class VideoListComponent implements OnInit { params.search = this.search.value; } - this.router.navigate(['VideosList', params]); - this.getVideos(); + this.router.navigate(['/videos/list', params]); + } + + searchChanged(search: Search) { + this.searchService.searchChanged.next(search); } } diff --git a/client/src/app/videos/video-list/video-miniature.component.html b/client/src/app/videos/video-list/video-miniature.component.html index 244254b5a..92e19bb8b 100644 --- a/client/src/app/videos/video-list/video-miniature.component.html +++ b/client/src/app/videos/video-list/video-miniature.component.html @@ -1,6 +1,6 @@
video thumbnail @@ -12,11 +12,15 @@ >
- - {{ video.name }} - + + {{ video.name }} - by {{ video.by }} + + {{ tag }} + + + + by {{ video.by }} on {{ video.createdDate | date:'short' }}
diff --git a/client/src/app/videos/video-list/video-miniature.component.scss b/client/src/app/videos/video-list/video-miniature.component.scss index 3aa0ca63b..40d37b83f 100644 --- a/client/src/app/videos/video-list/video-miniature.component.scss +++ b/client/src/app/videos/video-list/video-miniature.component.scss @@ -1,5 +1,5 @@ .video-miniature { - height: 200px; + margin-top: 30px; display: inline-block; position: relative; @@ -35,13 +35,34 @@ .video-miniature-informations { margin-left: 3px; + width: 200px; - .video-miniature-name { + .video-miniature-name-tags { display: block; - font-weight: bold; - &:hover { - text-decoration: none; + .video-miniature-name { + font-weight: bold; + + &:hover { + text-decoration: none; + } + + &::after { + content: '\002022'; + margin-left: 3px; + } + } + + .video-miniature-tag { + font-size: 12px; + cursor: pointer; + transition: opacity 0.5s; + position: relative; + top: -2px; + + &:hover { + opacity: 0.9; + } } } @@ -49,7 +70,16 @@ display: block; margin-left: 1px; font-size: 11px; - color: rgba(0, 0, 0, 0.5); + color: rgb(54, 118, 173); + } + + .video-miniature-author { + transition: opacity 0.5s; + + &:hover { + text-decoration: none; + opacity: 0.9; + } } } } diff --git a/client/src/app/videos/video-list/video-miniature.component.ts b/client/src/app/videos/video-list/video-miniature.component.ts index 639339b44..90645d67f 100644 --- a/client/src/app/videos/video-list/video-miniature.component.ts +++ b/client/src/app/videos/video-list/video-miniature.component.ts @@ -1,6 +1,6 @@ import { DatePipe } from '@angular/common'; import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { ROUTER_DIRECTIVES } from '@angular/router-deprecated'; +import { ROUTER_DIRECTIVES } from '@angular/router'; import { Video, VideoService } from '../shared'; import { User } from '../../shared'; diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts index 05e844f60..99188bfb3 100644 --- a/client/src/app/videos/video-watch/video-watch.component.ts +++ b/client/src/app/videos/video-watch/video-watch.component.ts @@ -1,5 +1,5 @@ import { Component, ElementRef, OnInit } from '@angular/core'; -import { CanDeactivate, ComponentInstruction, RouteParams } from '@angular/router-deprecated'; +import { CanDeactivate, RouteSegment } from '@angular/router'; import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; @@ -30,7 +30,7 @@ export class VideoWatchComponent implements OnInit, CanDeactivate { constructor( private elementRef: ElementRef, - private routeParams: RouteParams, + private routeSegment: RouteSegment, private videoService: VideoService, private webTorrentService: WebTorrentService ) {} @@ -74,7 +74,7 @@ export class VideoWatchComponent implements OnInit, CanDeactivate { } ngOnInit() { - let id = this.routeParams.get('id'); + let id = this.routeSegment.getParam('id'); this.videoService.getVideo(id).subscribe( video => { this.video = video; @@ -84,11 +84,11 @@ export class VideoWatchComponent implements OnInit, CanDeactivate { ); } - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { + routerCanDeactivate() { console.log('Removing video from webtorrent.'); clearInterval(this.torrentInfosInterval); this.webTorrentService.remove(this.video.magnetUri); - return true; + return Promise.resolve(true); } private loadTooLong() { diff --git a/client/src/vendor.ts b/client/src/vendor.ts index 437d05822..cf1524578 100644 --- a/client/src/vendor.ts +++ b/client/src/vendor.ts @@ -9,7 +9,7 @@ import '@angular/platform-browser-dynamic'; import '@angular/core'; import '@angular/common'; import '@angular/http'; -import '@angular/router-deprecated'; +import '@angular/router'; // RxJS import 'rxjs/Observable'; diff --git a/client/tsconfig.json b/client/tsconfig.json index fdcf742ea..54b931ba6 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -37,6 +37,7 @@ "src/app/shared/search/search-field.type.ts", "src/app/shared/search/search.component.ts", "src/app/shared/search/search.model.ts", + "src/app/shared/search/search.service.ts", "src/app/shared/users/auth-status.model.ts", "src/app/shared/users/auth.service.ts", "src/app/shared/users/index.ts", -- 2.41.0