From 2d3741d6d92e9bd1f41694c7442a6d1da434e1f2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 30 Aug 2018 14:58:00 +0200 Subject: Videos overview page: first version --- .../+video-channels/video-channels.component.html | 2 +- .../+video-channels/video-channels.component.ts | 6 ++ client/src/app/menu/menu.component.html | 5 ++ client/src/app/menu/menu.component.scss | 5 ++ client/src/app/search/search.component.html | 2 +- client/src/app/search/search.component.scss | 9 --- client/src/app/shared/overview/index.ts | 1 + client/src/app/shared/overview/overview.service.ts | 76 ++++++++++++++++++++++ .../app/shared/overview/videos-overview.model.ts | 19 ++++++ client/src/app/shared/shared.module.ts | 2 + .../src/app/shared/video/abstract-video-list.html | 8 +-- client/src/app/shared/video/video.service.ts | 8 --- .../videos/+video-watch/video-watch.component.html | 28 ++++---- .../video-list/video-overview.component.html | 35 ++++++++++ .../video-list/video-overview.component.scss | 22 +++++++ .../videos/video-list/video-overview.component.ts | 56 ++++++++++++++++ client/src/app/videos/videos-routing.module.ts | 10 +++ client/src/app/videos/videos.module.ts | 4 +- client/src/assets/images/menu/globe.svg | 18 +++++ client/src/sass/application.scss | 9 +++ 20 files changed, 285 insertions(+), 40 deletions(-) create mode 100644 client/src/app/shared/overview/index.ts create mode 100644 client/src/app/shared/overview/overview.service.ts create mode 100644 client/src/app/shared/overview/videos-overview.model.ts create mode 100644 client/src/app/videos/video-list/video-overview.component.html create mode 100644 client/src/app/videos/video-list/video-overview.component.scss create mode 100644 client/src/app/videos/video-list/video-overview.component.ts create mode 100644 client/src/assets/images/menu/globe.svg (limited to 'client') diff --git a/client/src/app/+video-channels/video-channels.component.html b/client/src/app/+video-channels/video-channels.component.html index 1941a2eab..e5a32dc92 100644 --- a/client/src/app/+video-channels/video-channels.component.html +++ b/client/src/app/+video-channels/video-channels.component.html @@ -9,7 +9,7 @@
{{ videoChannel.displayName }}
{{ videoChannel.nameWithHost }}
- +
{{ videoChannel.followersCount }} subscribers
diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts index 57c55d286..ee2c86915 100644 --- a/client/src/app/+video-channels/video-channels.component.ts +++ b/client/src/app/+video-channels/video-channels.component.ts @@ -5,6 +5,7 @@ import { VideoChannelService } from '@app/shared/video-channel/video-channel.ser import { RestExtractor } from '@app/shared' import { catchError, distinctUntilChanged, map, switchMap } from 'rxjs/operators' import { Subscription } from 'rxjs' +import { AuthService } from '@app/core' @Component({ templateUrl: './video-channels.component.html', @@ -17,6 +18,7 @@ export class VideoChannelsComponent implements OnInit, OnDestroy { constructor ( private route: ActivatedRoute, + private authService: AuthService, private videoChannelService: VideoChannelService, private restExtractor: RestExtractor ) { } @@ -36,4 +38,8 @@ export class VideoChannelsComponent implements OnInit, OnDestroy { ngOnDestroy () { if (this.routeSub) this.routeSub.unsubscribe() } + + isUserLoggedIn () { + return this.authService.isLoggedIn() + } } diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index bd03af9b3..8fe6797d6 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html @@ -47,6 +47,11 @@ Subscriptions + + + Overview + + Trending diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index 606fea961..8539c0e56 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss @@ -141,6 +141,11 @@ menu { background-image: url('../../assets/images/menu/subscriptions.svg'); } + &.icon-videos-overview { + position: relative; + background-image: url('../../assets/images/menu/globe.svg'); + } + &.icon-videos-trending { position: relative; top: -2px; diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html index d2ed1f881..b35a46ec9 100644 --- a/client/src/app/search/search.component.html +++ b/client/src/app/search/search.component.html @@ -22,7 +22,7 @@ -
+
No results found
diff --git a/client/src/app/search/search.component.scss b/client/src/app/search/search.component.scss index e5dfddcc5..f394099e2 100644 --- a/client/src/app/search/search.component.scss +++ b/client/src/app/search/search.component.scss @@ -1,15 +1,6 @@ @import '_variables'; @import '_mixins'; -.no-result { - height: 40vh; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - font-weight: $font-semibold; -} - .search-result { padding: 40px; diff --git a/client/src/app/shared/overview/index.ts b/client/src/app/shared/overview/index.ts new file mode 100644 index 000000000..2f7e41298 --- /dev/null +++ b/client/src/app/shared/overview/index.ts @@ -0,0 +1 @@ +export * from './overview.service' diff --git a/client/src/app/shared/overview/overview.service.ts b/client/src/app/shared/overview/overview.service.ts new file mode 100644 index 000000000..4a4714af6 --- /dev/null +++ b/client/src/app/shared/overview/overview.service.ts @@ -0,0 +1,76 @@ +import { catchError, map, switchMap, tap } from 'rxjs/operators' +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { forkJoin, Observable, of } from 'rxjs' +import { VideosOverview as VideosOverviewServer, peertubeTranslate } from '../../../../../shared/models' +import { environment } from '../../../environments/environment' +import { RestExtractor } from '../rest/rest-extractor.service' +import { RestService } from '../rest/rest.service' +import { VideosOverview } from '@app/shared/overview/videos-overview.model' +import { VideoService } from '@app/shared/video/video.service' +import { ServerService } from '@app/core' +import { immutableAssign } from '@app/shared/misc/utils' + +@Injectable() +export class OverviewService { + static BASE_OVERVIEW_URL = environment.apiUrl + '/api/v1/overviews/' + + constructor ( + private authHttp: HttpClient, + private restExtractor: RestExtractor, + private restService: RestService, + private videosService: VideoService, + private serverService: ServerService + ) {} + + getVideosOverview (): Observable { + return this.authHttp + .get(OverviewService.BASE_OVERVIEW_URL + 'videos') + .pipe( + switchMap(serverVideosOverview => this.updateVideosOverview(serverVideosOverview)), + catchError(err => this.restExtractor.handleError(err)) + ) + } + + private updateVideosOverview (serverVideosOverview: VideosOverviewServer): Observable { + const observables: Observable[] = [] + const videosOverviewResult: VideosOverview = { + tags: [], + categories: [], + channels: [] + } + + // Build videos objects + for (const key of Object.keys(serverVideosOverview)) { + for (const object of serverVideosOverview[ key ]) { + observables.push( + of(object.videos) + .pipe( + switchMap(videos => this.videosService.extractVideos({ total: 0, data: videos })), + map(result => result.videos), + tap(videos => { + videosOverviewResult[key].push(immutableAssign(object, { videos })) + }) + ) + ) + } + } + + return forkJoin(observables) + .pipe( + // Translate categories + switchMap(() => { + return this.serverService.localeObservable + .pipe( + tap(translations => { + for (const c of videosOverviewResult.categories) { + c.category.label = peertubeTranslate(c.category.label, translations) + } + }) + ) + }), + map(() => videosOverviewResult) + ) + } + +} diff --git a/client/src/app/shared/overview/videos-overview.model.ts b/client/src/app/shared/overview/videos-overview.model.ts new file mode 100644 index 000000000..cf02bdb3d --- /dev/null +++ b/client/src/app/shared/overview/videos-overview.model.ts @@ -0,0 +1,19 @@ +import { VideoChannelAttribute, VideoConstant, VideosOverview as VideosOverviewServer } from '../../../../../shared/models' +import { Video } from '@app/shared/video/video.model' + +export class VideosOverview implements VideosOverviewServer { + channels: { + channel: VideoChannelAttribute + videos: Video[] + }[] + + categories: { + category: VideoConstant + videos: Video[] + }[] + + tags: { + tag: string + videos: Video[] + }[] +} diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 2cbaaf4ae..b96a9aa41 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -52,6 +52,7 @@ import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.com import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription' import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component' +import { OverviewService } from '@app/shared/overview' @NgModule({ imports: [ @@ -154,6 +155,7 @@ import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-fe VideoValidatorsService, VideoCaptionsValidatorsService, VideoBlacklistValidatorsService, + OverviewService, I18nPrimengCalendarService, ScreenService, diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index d4b00c07c..0f48b9a64 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html @@ -4,7 +4,7 @@
-
No results.
+
No results.
- - +
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index 558db9543..7cc98c77a 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -51,14 +51,6 @@ export class VideoService { ) } - viewVideo (uuid: string): Observable { - return this.authHttp.post(this.getVideoViewUrl(uuid), {}) - .pipe( - map(this.restExtractor.extractDataBool), - catchError(err => this.restExtractor.handleError(err)) - ) - } - updateVideo (video: VideoEdit) { const language = video.language || null const licence = video.licence || null 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 333c9d11b..2c8305777 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html @@ -38,7 +38,7 @@ Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views - +
{{ video.name }}
@@ -46,7 +46,7 @@
Published {{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views
-
+
@@ -56,57 +56,57 @@ >
- +
- +
Support
- +
Share
- +
- +
- +
diff --git a/client/src/app/videos/video-list/video-overview.component.html b/client/src/app/videos/video-list/video-overview.component.html new file mode 100644 index 000000000..9282dd59c --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.html @@ -0,0 +1,35 @@ +
+ +
No results.
+ + + +
+ + +
+ +
+
+ + + +
diff --git a/client/src/app/videos/video-list/video-overview.component.scss b/client/src/app/videos/video-list/video-overview.component.scss new file mode 100644 index 000000000..8d66cf80a --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.scss @@ -0,0 +1,22 @@ +@import '_variables'; +@import '_mixins'; + +.section { + padding-top: 10px; + + &:first-child { + padding-top: 30px; + } +} + +.section-title { + font-size: 17px; + font-weight: $font-semibold; + margin-bottom: 20px; + + a { + @include disable-default-a-behaviour; + + color: #000; + } +} \ No newline at end of file diff --git a/client/src/app/videos/video-list/video-overview.component.ts b/client/src/app/videos/video-list/video-overview.component.ts new file mode 100644 index 000000000..c758e115c --- /dev/null +++ b/client/src/app/videos/video-list/video-overview.component.ts @@ -0,0 +1,56 @@ +import { Component, OnInit } from '@angular/core' +import { AuthService } from '@app/core' +import { NotificationsService } from 'angular2-notifications' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { VideosOverview } from '@app/shared/overview/videos-overview.model' +import { OverviewService } from '@app/shared/overview' +import { Video } from '@app/shared/video/video.model' + +@Component({ + selector: 'my-video-overview', + templateUrl: './video-overview.component.html', + styleUrls: [ './video-overview.component.scss' ] +}) +export class VideoOverviewComponent implements OnInit { + overview: VideosOverview = { + categories: [], + channels: [], + tags: [] + } + notResults = false + + constructor ( + private i18n: I18n, + private notificationsService: NotificationsService, + private authService: AuthService, + private overviewService: OverviewService + ) { } + + get user () { + return this.authService.getUser() + } + + ngOnInit () { + this.overviewService.getVideosOverview() + .subscribe( + overview => { + this.overview = overview + + if ( + this.overview.categories.length === 0 && + this.overview.channels.length === 0 && + this.overview.tags.length === 0 + ) this.notResults = true + }, + + err => { + console.log(err) + this.notificationsService.error('Error', err.text) + } + ) + } + + buildVideoChannelBy (object: { videos: Video[] }) { + return object.videos[0].byVideoChannel + } +} diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 18ed52570..58988ffd1 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts @@ -6,6 +6,7 @@ import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.c import { VideoTrendingComponent } from './video-list/video-trending.component' import { VideosComponent } from './videos.component' import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' +import { VideoOverviewComponent } from '@app/videos/video-list/video-overview.component' const videosRoutes: Routes = [ { @@ -13,6 +14,15 @@ const videosRoutes: Routes = [ component: VideosComponent, canActivateChild: [ MetaGuard ], children: [ + { + path: 'overview', + component: VideoOverviewComponent, + data: { + meta: { + title: 'Videos overview' + } + } + }, { path: 'trending', component: VideoTrendingComponent, diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts index 3c3877273..5cf1e944f 100644 --- a/client/src/app/videos/videos.module.ts +++ b/client/src/app/videos/videos.module.ts @@ -6,6 +6,7 @@ import { VideoTrendingComponent } from './video-list/video-trending.component' import { VideosRoutingModule } from './videos-routing.module' import { VideosComponent } from './videos.component' import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-user-subscriptions.component' +import { VideoOverviewComponent } from '@app/videos/video-list/video-overview.component' @NgModule({ imports: [ @@ -19,7 +20,8 @@ import { VideoUserSubscriptionsComponent } from '@app/videos/video-list/video-us VideoTrendingComponent, VideoRecentlyAddedComponent, VideoLocalComponent, - VideoUserSubscriptionsComponent + VideoUserSubscriptionsComponent, + VideoOverviewComponent ], exports: [ diff --git a/client/src/assets/images/menu/globe.svg b/client/src/assets/images/menu/globe.svg new file mode 100644 index 000000000..a4b3db9c5 --- /dev/null +++ b/client/src/assets/images/menu/globe.svg @@ -0,0 +1,18 @@ + + + + globe + Created with Sketch. + + + + + + + + + + + + + diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index 21df23c18..38b7ea8d4 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss @@ -293,6 +293,15 @@ table { } } +.no-results { + height: 40vh; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + font-weight: $font-semibold; +} + @media screen and (max-width: 900px) { .main-col { &, &.expanded { -- cgit v1.2.3