From 67ed6552b831df66713bac9e672738796128d33f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 23 Jun 2020 14:10:17 +0200 Subject: Reorganize client shared modules --- .../my-account-video-channel-create.component.ts | 82 +++++++++++ .../my-account-video-channel-edit.component.html | 105 ++++++++++++++ .../my-account-video-channel-edit.component.scss | 67 +++++++++ .../my-account-video-channel-edit.ts | 19 +++ .../my-account-video-channel-update.component.ts | 135 +++++++++++++++++ .../my-account-video-channels-routing.module.ts | 41 ++++++ .../my-account-video-channels.component.html | 35 +++++ .../my-account-video-channels.component.scss | 115 +++++++++++++++ .../my-account-video-channels.component.ts | 154 ++++++++++++++++++++ .../my-account-video-channels.module.ts | 31 ++++ .../my-account-blocklist.component.ts | 6 +- .../my-account-server-blocklist.component.ts | 6 +- .../my-account-history.component.ts | 25 ++-- .../my-account-notifications.component.ts | 2 +- .../my-account-accept-ownership.component.ts | 12 +- .../my-account-ownership.component.ts | 10 +- .../app/+my-account/my-account-routing.module.ts | 35 +++-- .../my-account-change-email.component.ts | 13 +- .../my-account-change-password.component.ts | 10 +- .../my-account-danger-zone.component.ts | 5 +- .../my-account-interface/index.ts | 1 - .../my-account-interface-settings.component.html | 17 --- .../my-account-interface-settings.component.scss | 21 --- .../my-account-interface-settings.component.ts | 89 ------------ ...y-account-notification-preferences.component.ts | 11 +- .../my-account-profile.component.ts | 9 +- .../my-account-settings.component.html | 4 +- .../my-account-settings.component.ts | 9 +- .../my-account-video-settings/index.ts | 1 - .../my-account-video-settings.component.html | 75 ---------- .../my-account-video-settings.component.scss | 24 ---- .../my-account-video-settings.component.ts | 142 ------------------ .../my-account-subscriptions.component.ts | 9 +- .../my-account-video-channel-create.component.ts | 83 ----------- .../my-account-video-channel-edit.component.html | 105 -------------- .../my-account-video-channel-edit.component.scss | 67 --------- .../my-account-video-channel-edit.ts | 19 --- .../my-account-video-channel-update.component.ts | 138 ------------------ .../my-account-video-channels-routing.module.ts | 41 ------ .../my-account-video-channels.component.html | 35 ----- .../my-account-video-channels.component.scss | 115 --------------- .../my-account-video-channels.component.ts | 159 --------------------- .../my-account-video-channels.module.ts | 25 ---- .../my-account-video-imports.component.ts | 9 +- .../my-account-video-playlist-create.component.ts | 9 +- .../my-account-video-playlist-edit.ts | 4 +- ...my-account-video-playlist-elements.component.ts | 19 +-- .../my-account-video-playlist-update.component.ts | 16 +-- .../my-account-video-playlists.component.ts | 13 +- .../my-account-videos.component.ts | 22 ++- .../video-change-ownership.component.ts | 8 +- client/src/app/+my-account/my-account.component.ts | 2 +- client/src/app/+my-account/my-account.module.ts | 72 ++++++---- .../shared/actor-avatar-info.component.html | 24 ---- .../shared/actor-avatar-info.component.scss | 71 --------- .../shared/actor-avatar-info.component.ts | 66 --------- .../+my-account/top-menu-dropdown.component.html | 50 +++++++ .../+my-account/top-menu-dropdown.component.scss | 56 ++++++++ .../app/+my-account/top-menu-dropdown.component.ts | 131 +++++++++++++++++ 59 files changed, 1170 insertions(+), 1509 deletions(-) create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-create.component.ts create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.html create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.scss create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.ts create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-update.component.ts create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channels-routing.module.ts create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.html create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.scss create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.ts create mode 100644 client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.module.ts delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-interface/index.ts delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.html delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.scss delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.ts delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-video-settings/index.ts delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss delete mode 100644 client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts delete mode 100644 client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts delete mode 100644 client/src/app/+my-account/shared/actor-avatar-info.component.html delete mode 100644 client/src/app/+my-account/shared/actor-avatar-info.component.scss delete mode 100644 client/src/app/+my-account/shared/actor-avatar-info.component.ts create mode 100644 client/src/app/+my-account/top-menu-dropdown.component.html create mode 100644 client/src/app/+my-account/top-menu-dropdown.component.scss create mode 100644 client/src/app/+my-account/top-menu-dropdown.component.ts (limited to 'client/src/app/+my-account') diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-create.component.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-create.component.ts new file mode 100644 index 000000000..039c389e4 --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-create.component.ts @@ -0,0 +1,82 @@ +import { Component, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { AuthService, Notifier } from '@app/core' +import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms' +import { VideoChannelService } from '@app/shared/shared-main' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { VideoChannelCreate } from '@shared/models' +import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' + +@Component({ + selector: 'my-account-video-channel-create', + templateUrl: './my-account-video-channel-edit.component.html', + styleUrls: [ './my-account-video-channel-edit.component.scss' ] +}) +export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelEdit implements OnInit { + error: string + + constructor ( + protected formValidatorService: FormValidatorService, + private authService: AuthService, + private videoChannelValidatorsService: VideoChannelValidatorsService, + private notifier: Notifier, + private router: Router, + private videoChannelService: VideoChannelService, + private i18n: I18n + ) { + super() + } + + get instanceHost () { + return window.location.host + } + + ngOnInit () { + this.buildForm({ + name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME, + 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, + description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, + support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT + }) + } + + formValidated () { + this.error = undefined + + const body = this.form.value + const videoChannelCreate: VideoChannelCreate = { + name: body.name, + displayName: body['display-name'], + description: body.description || null, + support: body.support || null + } + + this.videoChannelService.createVideoChannel(videoChannelCreate).subscribe( + () => { + this.authService.refreshUserInformation() + + this.notifier.success( + this.i18n('Video channel {{videoChannelName}} created.', { videoChannelName: videoChannelCreate.displayName }) + ) + this.router.navigate([ '/my-account', 'video-channels' ]) + }, + + err => { + if (err.status === 409) { + this.error = this.i18n('This name already exists on this instance.') + return + } + + this.error = err.message + } + ) + } + + isCreation () { + return true + } + + getFormButtonTitle () { + return this.i18n('Create') + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.html b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.html new file mode 100644 index 000000000..048d143cd --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.html @@ -0,0 +1,105 @@ + + +
{{ error }}
+ +
+ +
+
+
NEW CHANNEL
+
CHANNEL
+
+ +
+ +
+ +
+ +
+ @{{ instanceHost }} +
+
+
+ {{ formErrors['name'] }} +
+
+ + + +
+ + +
+ {{ formErrors['display-name'] }} +
+
+ +
+ + +
+ {{ formErrors.description }} +
+
+ +
+ + + +
+ {{ formErrors.support }} +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+
diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.scss b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.scss new file mode 100644 index 000000000..8f8af655c --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.component.scss @@ -0,0 +1,67 @@ +@import '_variables'; +@import '_mixins'; + +label { + font-weight: $font-regular; + font-size: 100%; +} + +.video-channel-title { + @include settings-big-title; +} + +my-actor-avatar-info { + display: block; + margin-bottom: 20px; +} + +.input-group { + @include peertube-input-group(fit-content); +} + +.input-group-append { + height: 30px; +} + +input { + &[type=text] { + @include peertube-input-text(340px); + + display: block; + + &#name { + width: auto; + flex-grow: 1; + } + } + + &[type=submit] { + @include peertube-button; + @include orange-button; + margin-left: auto; + } +} + +textarea { + @include peertube-textarea(500px, 150px); + + display: block; +} + +.peertube-select-container { + @include peertube-select-container(340px); +} + +.breadcrumb { + @include breadcrumb; +} + +@media screen and (max-width: $small-view) { + input[type=text]#name { + width: auto !important; + } + + label[for=name] + div, textarea { + width: 100%; + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.ts new file mode 100644 index 000000000..710c51d8e --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-edit.ts @@ -0,0 +1,19 @@ +import { FormReactive } from '@app/shared/shared-forms' +import { VideoChannel } from '@app/shared/shared-main' + +export abstract class MyAccountVideoChannelEdit extends FormReactive { + // We need it even in the create component because it's used in the edit template + videoChannelToUpdate: VideoChannel + instanceHost: string + + abstract isCreation (): boolean + abstract getFormButtonTitle (): string + + // We need this method so angular does not complain in child template that doesn't need this + onAvatarChange (formData: FormData) { /* empty */ } + + // Should be implemented by the child + isBulkUpdateVideosDisplayed () { + return false + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-update.component.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-update.component.ts new file mode 100644 index 000000000..489c437ea --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channel-update.component.ts @@ -0,0 +1,135 @@ +import { Subscription } from 'rxjs' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { AuthService, Notifier, ServerService } from '@app/core' +import { FormValidatorService, VideoChannelValidatorsService } from '@app/shared/shared-forms' +import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { ServerConfig, VideoChannelUpdate } from '@shared/models' +import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' + +@Component({ + selector: 'my-account-video-channel-update', + templateUrl: './my-account-video-channel-edit.component.html', + styleUrls: [ './my-account-video-channel-edit.component.scss' ] +}) +export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelEdit implements OnInit, OnDestroy { + error: string + videoChannelToUpdate: VideoChannel + + private paramsSub: Subscription + private oldSupportField: string + private serverConfig: ServerConfig + + constructor ( + protected formValidatorService: FormValidatorService, + private authService: AuthService, + private videoChannelValidatorsService: VideoChannelValidatorsService, + private notifier: Notifier, + private router: Router, + private route: ActivatedRoute, + private videoChannelService: VideoChannelService, + private i18n: I18n, + private serverService: ServerService + ) { + super() + } + + ngOnInit () { + this.serverConfig = this.serverService.getTmpConfig() + this.serverService.getConfig() + .subscribe(config => this.serverConfig = config) + + this.buildForm({ + 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, + description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, + support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT, + bulkVideosSupportUpdate: null + }) + + this.paramsSub = this.route.params.subscribe(routeParams => { + const videoChannelId = routeParams['videoChannelId'] + + this.videoChannelService.getVideoChannel(videoChannelId).subscribe( + videoChannelToUpdate => { + this.videoChannelToUpdate = videoChannelToUpdate + + this.oldSupportField = videoChannelToUpdate.support + + this.form.patchValue({ + 'display-name': videoChannelToUpdate.displayName, + description: videoChannelToUpdate.description, + support: videoChannelToUpdate.support + }) + }, + + err => this.error = err.message + ) + }) + } + + ngOnDestroy () { + if (this.paramsSub) this.paramsSub.unsubscribe() + } + + formValidated () { + this.error = undefined + + const body = this.form.value + const videoChannelUpdate: VideoChannelUpdate = { + displayName: body['display-name'], + description: body.description || null, + support: body.support || null, + bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false + } + + this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe( + () => { + this.authService.refreshUserInformation() + + this.notifier.success( + this.i18n('Video channel {{videoChannelName}} updated.', { videoChannelName: videoChannelUpdate.displayName }) + ) + + this.router.navigate([ '/my-account', 'video-channels' ]) + }, + + err => this.error = err.message + ) + } + + onAvatarChange (formData: FormData) { + this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.name, formData) + .subscribe( + data => { + this.notifier.success(this.i18n('Avatar changed.')) + + this.videoChannelToUpdate.updateAvatar(data.avatar) + }, + + err => this.notifier.error(err.message) + ) + } + + get maxAvatarSize () { + return this.serverConfig.avatar.file.size.max + } + + get avatarExtensions () { + return this.serverConfig.avatar.file.extensions.join(',') + } + + isCreation () { + return false + } + + getFormButtonTitle () { + return this.i18n('Update') + } + + isBulkUpdateVideosDisplayed () { + if (this.oldSupportField === undefined) return false + + return this.oldSupportField !== this.form.value['support'] + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels-routing.module.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels-routing.module.ts new file mode 100644 index 000000000..94037e18f --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels-routing.module.ts @@ -0,0 +1,41 @@ +import { NgModule } from '@angular/core' +import { RouterModule, Routes } from '@angular/router' +import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component' +import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component' +import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component' + +const myAccountVideoChannelsRoutes: Routes = [ + { + path: '', + component: MyAccountVideoChannelsComponent, + data: { + meta: { + title: 'Account video channels' + } + } + }, + { + path: 'create', + component: MyAccountVideoChannelCreateComponent, + data: { + meta: { + title: 'Create new video channel' + } + } + }, + { + path: 'update/:videoChannelId', + component: MyAccountVideoChannelUpdateComponent, + data: { + meta: { + title: 'Update video channel' + } + } + } +] + +@NgModule({ + imports: [ RouterModule.forChild(myAccountVideoChannelsRoutes) ], + exports: [ RouterModule ] +}) +export class MyAccountVideoChannelsRoutingModule {} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.html b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.html new file mode 100644 index 000000000..b2e8210d3 --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.html @@ -0,0 +1,35 @@ +

My channels

+
+ + + Create video channel + +
+ +
+
+ + Avatar + + +
+ +
{{ videoChannel.displayName }}
+
{{ videoChannel.nameWithHost }}
+
+ +
{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}
+ +
{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}
+ +
+ + +
+ +
+ +
+
+
+
diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.scss b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.scss new file mode 100644 index 000000000..76fb2cde0 --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.scss @@ -0,0 +1,115 @@ +@import '_variables'; +@import '_mixins'; + +.create-button { + @include create-button; +} + +::ng-deep .action-button { + &.action-button-edit { + margin-right: 10px; + } +} + +.video-channel { + @include row-blocks; + padding-bottom: 0; + + img { + @include avatar(80px); + + margin-right: 10px; + } + + .video-channel-info { + flex-grow: 1; + + a.video-channel-names { + @include disable-default-a-behaviour; + + width: fit-content; + display: flex; + align-items: baseline; + color: pvar(--mainForegroundColor); + + .video-channel-display-name { + font-weight: $font-semibold; + font-size: 18px; + } + + .video-channel-name { + font-size: 14px; + color: $grey-actor-name; + margin-left: 5px; + } + + .video-channel-followers { + + } + } + } + + .video-channel-buttons { + margin-top: 10px; + min-width: 190px; + } +} + +.video-channels-header { + text-align: right; + margin: 20px 0 50px; +} + +::ng-deep .chartjs-render-monitor { + position: relative; + top: 1px; +} + +@media screen and (max-width: $small-view) { + .video-channels-header { + text-align: center; + } + + .video-channel { + padding-bottom: 10px; + + .video-channel-info { + padding-bottom: 10px; + text-align: center; + + .video-channel-names { + flex-direction: column; + align-items: center !important; + margin: auto; + + .video-channel-name { + margin-left: 0px !important; + } + } + } + + img { + margin-right: 0; + } + + .video-channel-buttons { + align-self: center; + } + } +} + +@media screen and (min-width: breakpoint(lg)) { + :host-context(.main-col:not(.expanded)) { + .video-channel-buttons { + float: right; + } + } +} + +@media screen and (min-width: $small-view) { + :host-context(.expanded) { + .video-channel-buttons { + float: right; + } + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.ts new file mode 100644 index 000000000..70510d7c9 --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.component.ts @@ -0,0 +1,154 @@ +import { ChartData } from 'chart.js' +import { max, maxBy, min, minBy } from 'lodash-es' +import { flatMap } from 'rxjs/operators' +import { Component, OnInit } from '@angular/core' +import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core' +import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' +import { I18n } from '@ngx-translate/i18n-polyfill' + +@Component({ + selector: 'my-account-video-channels', + templateUrl: './my-account-video-channels.component.html', + styleUrls: [ './my-account-video-channels.component.scss' ] +}) +export class MyAccountVideoChannelsComponent implements OnInit { + videoChannels: VideoChannel[] = [] + videoChannelsChartData: ChartData[] + videoChannelsMinimumDailyViews = 0 + videoChannelsMaximumDailyViews: number + + private user: User + + constructor ( + private authService: AuthService, + private notifier: Notifier, + private confirmService: ConfirmService, + private videoChannelService: VideoChannelService, + private screenService: ScreenService, + private i18n: I18n + ) {} + + ngOnInit () { + this.user = this.authService.getUser() + + this.loadVideoChannels() + } + + get isInSmallView () { + return this.screenService.isInSmallView() + } + + get chartOptions () { + return { + legend: { + display: false + }, + scales: { + xAxes: [{ + display: false + }], + yAxes: [{ + display: false, + ticks: { + min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), + max: Math.max(1, this.videoChannelsMaximumDailyViews) + } + }] + }, + layout: { + padding: { + left: 15, + right: 15, + top: 10, + bottom: 0 + } + }, + elements: { + point: { + radius: 0 + } + }, + tooltips: { + mode: 'index', + intersect: false, + custom: function (tooltip: any) { + if (!tooltip) return + // disable displaying the color box + tooltip.displayColors = false + }, + callbacks: { + label: (tooltip: any, data: any) => `${tooltip.value} views` + } + }, + hover: { + mode: 'index', + intersect: false + } + } + } + + async deleteVideoChannel (videoChannel: VideoChannel) { + const res = await this.confirmService.confirmWithInput( + this.i18n( + // tslint:disable + 'Do you really want to delete {{channelDisplayName}}? It will delete {{videosCount}} videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!', + { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name } + ), + this.i18n( + 'Please type the display name of the video channel ({{displayName}}) to confirm', + { displayName: videoChannel.displayName } + ), + videoChannel.displayName, + this.i18n('Delete') + ) + if (res === false) return + + this.videoChannelService.removeVideoChannel(videoChannel) + .subscribe( + () => { + this.loadVideoChannels() + this.notifier.success( + this.i18n('Video channel {{videoChannelName}} deleted.', { videoChannelName: videoChannel.displayName }) + ) + }, + + error => this.notifier.error(error.message) + ) + } + + private loadVideoChannels () { + this.authService.userInformationLoaded + .pipe(flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true))) + .subscribe(res => { + this.videoChannels = res.data + + // chart data + this.videoChannelsChartData = this.videoChannels.map(v => ({ + labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), + datasets: [ + { + label: this.i18n('Views for the day'), + data: v.viewsPerDay.map(day => day.views), + fill: false, + borderColor: "#c6c6c6" + } + ] + } as ChartData)) + + // chart options that depend on chart data: + // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here + this.videoChannelsMinimumDailyViews = min( + this.videoChannels.map(v => minBy( // compute local minimum daily views for each channel, by their "views" attribute + v.viewsPerDay, + day => day.views + ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute + ) + this.videoChannelsMaximumDailyViews = max( + this.videoChannels.map(v => maxBy( // compute local maximum daily views for each channel, by their "views" attribute + v.viewsPerDay, + day => day.views + ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute + ) + }) + } +} diff --git a/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.module.ts b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.module.ts new file mode 100644 index 000000000..f8c6ad56b --- /dev/null +++ b/client/src/app/+my-account/+my-account-video-channels/my-account-video-channels.module.ts @@ -0,0 +1,31 @@ +import { ChartModule } from 'primeng/chart' +import { NgModule } from '@angular/core' +import { SharedFormModule } from '@app/shared/shared-forms' +import { SharedGlobalIconModule } from '@app/shared/shared-icons' +import { SharedMainModule } from '@app/shared/shared-main' +import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component' +import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component' +import { MyAccountVideoChannelsRoutingModule } from './my-account-video-channels-routing.module' +import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component' + +@NgModule({ + imports: [ + MyAccountVideoChannelsRoutingModule, + + ChartModule, + + SharedMainModule, + SharedFormModule, + SharedGlobalIconModule + ], + + declarations: [ + MyAccountVideoChannelsComponent, + MyAccountVideoChannelCreateComponent, + MyAccountVideoChannelUpdateComponent + ], + + exports: [], + providers: [] +}) +export class MyAccountVideoChannelsModule { } diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts index e48c39cdf..03ec75e25 100644 --- a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts +++ b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core' -import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' +import { BlocklistComponentType, GenericAccountBlocklistComponent } from '@app/shared/shared-moderation' @Component({ selector: 'my-account-blocklist', - styleUrls: [ '../../shared/blocklist/account-blocklist.component.scss' ], - templateUrl: '../../shared/blocklist/account-blocklist.component.html' + styleUrls: [ '../../shared/shared-moderation/account-blocklist.component.scss' ], + templateUrl: '../../shared/shared-moderation/account-blocklist.component.html' }) export class MyAccountBlocklistComponent extends GenericAccountBlocklistComponent { mode = BlocklistComponentType.Account diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts index cfaba1c7b..9b983a197 100644 --- a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts +++ b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core' -import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' +import { BlocklistComponentType, GenericServerBlocklistComponent } from '@app/shared/shared-moderation' @Component({ selector: 'my-account-server-blocklist', - styleUrls: [ '../../+admin/moderation/moderation.component.scss', '../../shared/blocklist/server-blocklist.component.scss' ], - templateUrl: '../../shared/blocklist/server-blocklist.component.html' + styleUrls: [ '../../+admin/moderation/moderation.component.scss', '../../shared/shared-moderation/server-blocklist.component.scss' ], + templateUrl: '../../shared/shared-moderation/server-blocklist.component.html' }) export class MyAccountServerBlocklistComponent extends GenericServerBlocklistComponent { mode = BlocklistComponentType.Account diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.ts b/client/src/app/+my-account/my-account-history/my-account-history.component.ts index 5f0ccee50..dc78b3d6e 100644 --- a/client/src/app/+my-account/my-account-history/my-account-history.component.ts +++ b/client/src/app/+my-account/my-account-history/my-account-history.component.ts @@ -1,17 +1,19 @@ import { Component, OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { immutableAssign } from '@app/shared/misc/utils' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' -import { AuthService } from '../../core/auth' -import { ConfirmService } from '../../core/confirm' -import { AbstractVideoList } from '../../shared/video/abstract-video-list' -import { VideoService } from '../../shared/video/video.service' +import { + AuthService, + ComponentPagination, + ConfirmService, + LocalStorageService, + Notifier, + ScreenService, + ServerService, + UserService +} from '@app/core' +import { immutableAssign } from '@app/helpers' +import { UserHistoryService } from '@app/shared/shared-main' +import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { I18n } from '@ngx-translate/i18n-polyfill' -import { ScreenService } from '@app/shared/misc/screen.service' -import { UserHistoryService } from '@app/shared/users/user-history.service' -import { UserService } from '@app/shared' -import { Notifier, ServerService } from '@app/core' -import { LocalStorageService } from '@app/shared/misc/storage.service' @Component({ selector: 'my-account-history', @@ -38,7 +40,6 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn protected screenService: ScreenService, protected storageService: LocalStorageService, private confirmService: ConfirmService, - private videoService: VideoService, private userHistoryService: UserHistoryService ) { super() diff --git a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.ts b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.ts index a50cb0fb9..0c1427d96 100644 --- a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.ts +++ b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.ts @@ -1,5 +1,5 @@ import { Component, ViewChild } from '@angular/core' -import { UserNotificationsComponent } from '@app/shared' +import { UserNotificationsComponent } from '@app/shared/shared-main' @Component({ templateUrl: './my-account-notifications.component.html', diff --git a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.ts b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.ts index d5682914e..0e62b5ca5 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.ts +++ b/client/src/app/+my-account/my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component.ts @@ -1,14 +1,10 @@ import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' import { AuthService, Notifier } from '@app/core' -import { FormReactive } from '@app/shared' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { VideoOwnershipService } from '@app/shared/video-ownership' -import { VideoChangeOwnership } from '../../../../../../shared/models/videos' -import { VideoAcceptOwnershipValidatorsService } from '@app/shared/forms/form-validators' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' -import { I18n } from '@ngx-translate/i18n-polyfill' +import { FormReactive, FormValidatorService, VideoAcceptOwnershipValidatorsService } from '@app/shared/shared-forms' +import { VideoChannelService, VideoOwnershipService } from '@app/shared/shared-main' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { VideoChangeOwnership, VideoChannel } from '@shared/models' @Component({ selector: 'my-account-accept-ownership', diff --git a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts index f0a6303d1..5167732c2 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts +++ b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.ts @@ -1,10 +1,8 @@ -import { Component, OnInit, ViewChild } from '@angular/core' -import { Notifier } from '@app/core' -import { RestPagination, RestTable } from '@app/shared' import { SortMeta } from 'primeng/api' -import { VideoChangeOwnership } from '../../../../../shared' -import { VideoOwnershipService } from '@app/shared/video-ownership' -import { Account } from '@app/shared/account/account.model' +import { Component, OnInit, ViewChild } from '@angular/core' +import { Notifier, RestPagination, RestTable } from '@app/core' +import { Account, VideoOwnershipService } from '@app/shared/shared-main' +import { VideoChangeOwnership } from '@shared/models' import { MyAccountAcceptOwnershipComponent } from './my-account-accept-ownership/my-account-accept-ownership.component' @Component({ diff --git a/client/src/app/+my-account/my-account-routing.module.ts b/client/src/app/+my-account/my-account-routing.module.ts index f6b711e09..ac9cf4cfd 100644 --- a/client/src/app/+my-account/my-account-routing.module.ts +++ b/client/src/app/+my-account/my-account-routing.module.ts @@ -2,26 +2,20 @@ import { NgModule } from '@angular/core' import { RouterModule, Routes } from '@angular/router' import { MetaGuard } from '@ngx-meta/core' import { LoginGuard } from '../core' -import { MyAccountComponent } from './my-account.component' +import { MyAccountBlocklistComponent } from './my-account-blocklist/my-account-blocklist.component' +import { MyAccountServerBlocklistComponent } from './my-account-blocklist/my-account-server-blocklist.component' +import { MyAccountHistoryComponent } from './my-account-history/my-account-history.component' +import { MyAccountNotificationsComponent } from './my-account-notifications/my-account-notifications.component' +import { MyAccountOwnershipComponent } from './my-account-ownership/my-account-ownership.component' import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' +import { MyAccountSubscriptionsComponent } from './my-account-subscriptions/my-account-subscriptions.component' +import { MyAccountVideoImportsComponent } from './my-account-video-imports/my-account-video-imports.component' +import { MyAccountVideoPlaylistCreateComponent } from './my-account-video-playlists/my-account-video-playlist-create.component' +import { MyAccountVideoPlaylistElementsComponent } from './my-account-video-playlists/my-account-video-playlist-elements.component' +import { MyAccountVideoPlaylistUpdateComponent } from './my-account-video-playlists/my-account-video-playlist-update.component' +import { MyAccountVideoPlaylistsComponent } from './my-account-video-playlists/my-account-video-playlists.component' import { MyAccountVideosComponent } from './my-account-videos/my-account-videos.component' -import { MyAccountVideoImportsComponent } from '@app/+my-account/my-account-video-imports/my-account-video-imports.component' -import { MyAccountSubscriptionsComponent } from '@app/+my-account/my-account-subscriptions/my-account-subscriptions.component' -import { MyAccountOwnershipComponent } from '@app/+my-account/my-account-ownership/my-account-ownership.component' -import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component' -import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component' -import { MyAccountHistoryComponent } from '@app/+my-account/my-account-history/my-account-history.component' -import { MyAccountNotificationsComponent } from '@app/+my-account/my-account-notifications/my-account-notifications.component' -import { MyAccountVideoPlaylistsComponent } from '@app/+my-account/my-account-video-playlists/my-account-video-playlists.component' -import { - MyAccountVideoPlaylistCreateComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component' -import { - MyAccountVideoPlaylistUpdateComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component' -import { - MyAccountVideoPlaylistElementsComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component' +import { MyAccountComponent } from './my-account.component' const myAccountRoutes: Routes = [ { @@ -46,7 +40,10 @@ const myAccountRoutes: Routes = [ { path: 'video-channels', - loadChildren: () => import('./my-account-video-channels/my-account-video-channels.module').then(m => m.MyAccountVideoChannelsModule) + loadChildren: () => { + return import('./+my-account-video-channels/my-account-video-channels.module') + .then(m => m.MyAccountVideoChannelsModule) + } }, { diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts index 9d406805f..5444b97ae 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts @@ -1,12 +1,10 @@ +import { forkJoin } from 'rxjs' +import { tap } from 'rxjs/operators' import { Component, OnInit } from '@angular/core' -import { AuthService, Notifier, ServerService } from '@app/core' -import { FormReactive, UserService } from '../../../shared' +import { AuthService, ServerService, UserService } from '@app/core' +import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' -import { User } from '../../../../../../shared' -import { tap } from 'rxjs/operators' -import { forkJoin } from 'rxjs' +import { User } from '@shared/models' @Component({ selector: 'my-account-change-email', @@ -21,7 +19,6 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni constructor ( protected formValidatorService: FormValidatorService, private userValidatorsService: UserValidatorsService, - private notifier: Notifier, private authService: AuthService, private userService: UserService, private serverService: ServerService, diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts index cbb068c7c..6a16f8a2c 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts @@ -1,11 +1,9 @@ +import { filter } from 'rxjs/operators' import { Component, OnInit } from '@angular/core' -import { AuthService, Notifier } from '@app/core' -import { FormReactive, UserService } from '../../../shared' +import { AuthService, Notifier, UserService } from '@app/core' +import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' -import { filter } from 'rxjs/operators' -import { User } from '../../../../../../shared' +import { User } from '@shared/models' @Component({ selector: 'my-account-change-password', diff --git a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts index 25d862867..ae6ac5387 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts @@ -1,9 +1,6 @@ import { Component, Input } from '@angular/core' -import { Notifier } from '@app/core' -import { AuthService, ConfirmService, RedirectService } from '../../../core' -import { UserService } from '../../../shared' +import { AuthService, ConfirmService, Notifier, RedirectService, User, UserService } from '@app/core' import { I18n } from '@ngx-translate/i18n-polyfill' -import { User } from '@app/shared' @Component({ selector: 'my-account-danger-zone', diff --git a/client/src/app/+my-account/my-account-settings/my-account-interface/index.ts b/client/src/app/+my-account/my-account-settings/my-account-interface/index.ts deleted file mode 100644 index 62fce79a8..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-interface/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './my-account-interface-settings.component' diff --git a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.html deleted file mode 100644 index 0d0ddc0f2..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.html +++ /dev/null @@ -1,17 +0,0 @@ -
- -
- - -
- -
-
- - -
diff --git a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.scss b/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.scss deleted file mode 100644 index 7818dfc02..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.scss +++ /dev/null @@ -1,21 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -label { - font-weight: $font-regular; - font-size: 100%; -} - -input[type=submit] { - @include peertube-button; - @include orange-button; - - display: block; - margin-top: 15px; -} - -.peertube-select-container { - @include peertube-select-container(340px); - - margin-bottom: 30px; -} diff --git a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.ts deleted file mode 100644 index b6c17c0e3..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-interface/my-account-interface-settings.component.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Component, Input, OnInit, OnDestroy } from '@angular/core' -import { Notifier, ServerService } from '@app/core' -import { ServerConfig, UserUpdateMe } from '../../../../../../shared' -import { AuthService } from '../../../core' -import { FormReactive } from '../../../shared/forms/form-reactive' -import { User, UserService } from '../../../shared/users' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { Subject, Subscription } from 'rxjs' - -@Component({ - selector: 'my-account-interface-settings', - templateUrl: './my-account-interface-settings.component.html', - styleUrls: [ './my-account-interface-settings.component.scss' ] -}) -export class MyAccountInterfaceSettingsComponent extends FormReactive implements OnInit, OnDestroy { - @Input() user: User = null - @Input() reactiveUpdate = false - @Input() notifyOnUpdate = true - @Input() userInformationLoaded: Subject - - formValuesWatcher: Subscription - - private serverConfig: ServerConfig - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private notifier: Notifier, - private userService: UserService, - private serverService: ServerService, - private i18n: I18n - ) { - super() - } - - get availableThemes () { - return this.serverConfig.theme.registered - .map(t => t.name) - } - - ngOnInit () { - this.serverConfig = this.serverService.getTmpConfig() - this.serverService.getConfig() - .subscribe(config => this.serverConfig = config) - - this.buildForm({ - theme: null - }) - - this.userInformationLoaded - .subscribe(() => { - this.form.patchValue({ - theme: this.user.theme - }) - - if (this.reactiveUpdate) { - this.formValuesWatcher = this.form.valueChanges.subscribe(val => this.updateInterfaceSettings()) - } - }) - } - - ngOnDestroy () { - this.formValuesWatcher?.unsubscribe() - } - - updateInterfaceSettings () { - const theme = this.form.value['theme'] - - const details: UserUpdateMe = { - theme - } - - if (this.authService.isLoggedIn()) { - this.userService.updateMyProfile(details).subscribe( - () => { - this.authService.refreshUserInformation() - - if (this.notifyOnUpdate) this.notifier.success(this.i18n('Interface settings updated.')) - }, - - err => this.notifier.error(err.message) - ) - } else { - this.userService.updateMyAnonymousProfile(details) - if (this.notifyOnUpdate) this.notifier.success(this.i18n('Interface settings updated.')) - } - } -} diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts index af17a0352..cfa514b26 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts @@ -1,11 +1,10 @@ +import { debounce } from 'lodash-es' +import { Subject } from 'rxjs' import { Component, Input, OnInit } from '@angular/core' -import { User } from '@app/shared' +import { Notifier, ServerService, User } from '@app/core' +import { UserNotificationService } from '@app/shared/shared-main' import { I18n } from '@ngx-translate/i18n-polyfill' -import { Subject } from 'rxjs' -import { UserNotificationSetting, UserNotificationSettingValue, UserRight } from '../../../../../../shared' -import { Notifier, ServerService } from '@app/core' -import { debounce } from 'lodash-es' -import { UserNotificationService } from '@app/shared/users/user-notification.service' +import { UserNotificationSetting, UserNotificationSettingValue, UserRight } from '@shared/models' @Component({ selector: 'my-account-notification-preferences', diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts index fcad5a6c2..b0d8494e7 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts @@ -1,11 +1,8 @@ +import { Subject } from 'rxjs' import { Component, Input, OnInit } from '@angular/core' -import { Notifier } from '@app/core' -import { FormReactive, UserService } from '../../../shared' -import { User } from '@app/shared' +import { Notifier, User, UserService } from '@app/core' +import { FormReactive, FormValidatorService, UserValidatorsService } from '@app/shared/shared-forms' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { Subject } from 'rxjs' -import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' @Component({ selector: 'my-account-profile', diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index 040b2130f..2826d8d83 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html @@ -34,7 +34,7 @@
- +
@@ -55,7 +55,7 @@
- +
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts index f73f3aa1e..4800be24b 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts @@ -1,11 +1,8 @@ -import { Component, OnInit, AfterViewChecked } from '@angular/core' -import { Notifier } from '@app/core' import { BytesPipe } from 'ngx-pipes' -import { AuthService } from '../../core' -import { User } from '../../shared' -import { UserService } from '../../shared/users' -import { I18n } from '@ngx-translate/i18n-polyfill' import { ViewportScroller } from '@angular/common' +import { AfterViewChecked, Component, OnInit } from '@angular/core' +import { AuthService, Notifier, User, UserService } from '@app/core' +import { I18n } from '@ngx-translate/i18n-polyfill' @Component({ selector: 'my-account-settings', diff --git a/client/src/app/+my-account/my-account-settings/my-account-video-settings/index.ts b/client/src/app/+my-account/my-account-settings/my-account-video-settings/index.ts deleted file mode 100644 index 1253bd369..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-video-settings/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './my-account-video-settings.component' diff --git a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html deleted file mode 100644 index 0dda33af2..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html +++ /dev/null @@ -1,75 +0,0 @@ -
-
- - - - - With Do not list or Blur thumbnails, a confirmation will be requested to watch the video. - - - - -
- -
-
- -
- - - - In Recently added, Trending, Local, Most liked and Search pages - - - -
- -
-
- - - -
- - - The sharing system implies that some technical information about your system (such as a public IP address) can be sent to other peers, but greatly helps to reduce server load. - - -
- -
- - - When on a video page, directly start playing the video. - - -
- -
- - - When a video ends, follow up with the next suggested video. - - -
- - -
diff --git a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss b/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss deleted file mode 100644 index 430250b87..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -label { - font-weight: $font-regular; - font-size: 100%; -} - -input[type=submit] { - @include peertube-button; - @include orange-button; - - margin-top: 15px; -} - -.peertube-select-container { - @include peertube-select-container(340px); - - margin-bottom: 30px; -} - -.form-group-select { - margin-bottom: 30px; -} diff --git a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts deleted file mode 100644 index 0aaa54cd7..000000000 --- a/client/src/app/+my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Component, Input, OnInit, OnDestroy } from '@angular/core' -import { Notifier, ServerService } from '@app/core' -import { UserUpdateMe } from '../../../../../../shared/models/users' -import { User, UserService } from '@app/shared/users' -import { AuthService } from '../../../core' -import { FormReactive } from '@app/shared/forms/form-reactive' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { forkJoin, Subject, Subscription } from 'rxjs' -import { SelectItem } from 'primeng/api' -import { first } from 'rxjs/operators' -import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' -import { pick } from 'lodash-es' - -@Component({ - selector: 'my-account-video-settings', - templateUrl: './my-account-video-settings.component.html', - styleUrls: [ './my-account-video-settings.component.scss' ] -}) -export class MyAccountVideoSettingsComponent extends FormReactive implements OnInit, OnDestroy { - @Input() user: User = null - @Input() reactiveUpdate = false - @Input() notifyOnUpdate = true - @Input() userInformationLoaded: Subject - - languageItems: SelectItem[] = [] - defaultNSFWPolicy: NSFWPolicyType - formValuesWatcher: Subscription - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private notifier: Notifier, - private userService: UserService, - private serverService: ServerService, - private i18n: I18n - ) { - super() - } - - ngOnInit () { - let oldForm: any - - this.buildForm({ - nsfwPolicy: null, - webTorrentEnabled: null, - autoPlayVideo: null, - autoPlayNextVideo: null, - videoLanguages: null - }) - - forkJoin([ - this.serverService.getVideoLanguages(), - this.serverService.getConfig(), - this.userInformationLoaded.pipe(first()) - ]).subscribe(([ languages, config ]) => { - this.languageItems = [ { label: this.i18n('Unknown language'), value: '_unknown' } ] - this.languageItems = this.languageItems - .concat(languages.map(l => ({ label: l.label, value: l.id }))) - - const videoLanguages = this.user.videoLanguages - ? this.user.videoLanguages - : this.languageItems.map(l => l.value) - - this.defaultNSFWPolicy = config.instance.defaultNSFWPolicy - - this.form.patchValue({ - nsfwPolicy: this.user.nsfwPolicy || this.defaultNSFWPolicy, - webTorrentEnabled: this.user.webTorrentEnabled, - autoPlayVideo: this.user.autoPlayVideo === true, - autoPlayNextVideo: this.user.autoPlayNextVideo, - videoLanguages - }) - - if (this.reactiveUpdate) { - oldForm = { ...this.form.value } - this.formValuesWatcher = this.form.valueChanges.subscribe((formValue: any) => { - const updatedKey = Object.keys(formValue).find(k => formValue[k] !== oldForm[k]) - oldForm = { ...this.form.value } - this.updateDetails([updatedKey]) - }) - } - }) - } - - ngOnDestroy () { - this.formValuesWatcher?.unsubscribe() - } - - updateDetails (onlyKeys?: string[]) { - const nsfwPolicy = this.form.value[ 'nsfwPolicy' ] - const webTorrentEnabled = this.form.value['webTorrentEnabled'] - const autoPlayVideo = this.form.value['autoPlayVideo'] - const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] - - let videoLanguages: string[] = this.form.value['videoLanguages'] - if (Array.isArray(videoLanguages)) { - if (videoLanguages.length === this.languageItems.length) { - videoLanguages = null // null means "All" - } else if (videoLanguages.length > 20) { - this.notifier.error('Too many languages are enabled. Please enable them all or stay below 20 enabled languages.') - return - } else if (videoLanguages.length === 0) { - this.notifier.error('You need to enabled at least 1 video language.') - return - } - } - - let details: UserUpdateMe = { - nsfwPolicy, - webTorrentEnabled, - autoPlayVideo, - autoPlayNextVideo, - videoLanguages - } - - if (onlyKeys) details = pick(details, onlyKeys) - - if (this.authService.isLoggedIn()) { - this.userService.updateMyProfile(details).subscribe( - () => { - this.authService.refreshUserInformation() - - if (this.notifyOnUpdate) this.notifier.success(this.i18n('Video settings updated.')) - }, - - err => this.notifier.error(err.message) - ) - } else { - this.userService.updateMyAnonymousProfile(details) - if (this.notifyOnUpdate) this.notifier.success(this.i18n('Display/Video settings updated.')) - } - } - - getDefaultVideoLanguageLabel () { - return this.i18n('No language') - } - - getSelectedVideoLanguageLabel () { - return this.i18n('{{\'{0} languages selected') - } -} diff --git a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts index b347fc3fe..390293a28 100644 --- a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts +++ b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts @@ -1,9 +1,8 @@ -import { Component, OnInit } from '@angular/core' -import { Notifier } from '@app/core' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { UserSubscriptionService } from '@app/shared/user-subscription' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' import { Subject } from 'rxjs' +import { Component, OnInit } from '@angular/core' +import { ComponentPagination, Notifier } from '@app/core' +import { VideoChannel } from '@app/shared/shared-main' +import { UserSubscriptionService } from '@app/shared/shared-user-subscription' @Component({ selector: 'my-account-subscriptions', diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts deleted file mode 100644 index a68f79b47..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Component, OnInit } from '@angular/core' -import { Router } from '@angular/router' -import { AuthService, Notifier } from '@app/core' -import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' -import { VideoChannelCreate } from '../../../../../shared/models/videos' -import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service' - -@Component({ - selector: 'my-account-video-channel-create', - templateUrl: './my-account-video-channel-edit.component.html', - styleUrls: [ './my-account-video-channel-edit.component.scss' ] -}) -export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelEdit implements OnInit { - error: string - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private videoChannelValidatorsService: VideoChannelValidatorsService, - private notifier: Notifier, - private router: Router, - private videoChannelService: VideoChannelService, - private i18n: I18n - ) { - super() - } - - get instanceHost () { - return window.location.host - } - - ngOnInit () { - this.buildForm({ - name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME, - 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, - description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, - support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT - }) - } - - formValidated () { - this.error = undefined - - const body = this.form.value - const videoChannelCreate: VideoChannelCreate = { - name: body.name, - displayName: body['display-name'], - description: body.description || null, - support: body.support || null - } - - this.videoChannelService.createVideoChannel(videoChannelCreate).subscribe( - () => { - this.authService.refreshUserInformation() - - this.notifier.success( - this.i18n('Video channel {{videoChannelName}} created.', { videoChannelName: videoChannelCreate.displayName }) - ) - this.router.navigate([ '/my-account', 'video-channels' ]) - }, - - err => { - if (err.status === 409) { - this.error = this.i18n('This name already exists on this instance.') - return - } - - this.error = err.message - } - ) - } - - isCreation () { - return true - } - - getFormButtonTitle () { - return this.i18n('Create') - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html deleted file mode 100644 index 048d143cd..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html +++ /dev/null @@ -1,105 +0,0 @@ - - -
{{ error }}
- -
- -
-
-
NEW CHANNEL
-
CHANNEL
-
- -
- -
- -
- -
- @{{ instanceHost }} -
-
-
- {{ formErrors['name'] }} -
-
- - - -
- - -
- {{ formErrors['display-name'] }} -
-
- -
- - -
- {{ formErrors.description }} -
-
- -
- - - -
- {{ formErrors.support }} -
-
- -
- -
- -
-
- -
-
-
- -
-
-
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss deleted file mode 100644 index 8f8af655c..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss +++ /dev/null @@ -1,67 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -label { - font-weight: $font-regular; - font-size: 100%; -} - -.video-channel-title { - @include settings-big-title; -} - -my-actor-avatar-info { - display: block; - margin-bottom: 20px; -} - -.input-group { - @include peertube-input-group(fit-content); -} - -.input-group-append { - height: 30px; -} - -input { - &[type=text] { - @include peertube-input-text(340px); - - display: block; - - &#name { - width: auto; - flex-grow: 1; - } - } - - &[type=submit] { - @include peertube-button; - @include orange-button; - margin-left: auto; - } -} - -textarea { - @include peertube-textarea(500px, 150px); - - display: block; -} - -.peertube-select-container { - @include peertube-select-container(340px); -} - -.breadcrumb { - @include breadcrumb; -} - -@media screen and (max-width: $small-view) { - input[type=text]#name { - width: auto !important; - } - - label[for=name] + div, textarea { - width: 100%; - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts deleted file mode 100644 index 355cb4f55..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { FormReactive } from '@app/shared' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' - -export abstract class MyAccountVideoChannelEdit extends FormReactive { - // We need it even in the create component because it's used in the edit template - videoChannelToUpdate: VideoChannel - instanceHost: string - - abstract isCreation (): boolean - abstract getFormButtonTitle (): string - - // We need this method so angular does not complain in child template that doesn't need this - onAvatarChange (formData: FormData) { /* empty */ } - - // Should be implemented by the child - isBulkUpdateVideosDisplayed () { - return false - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts deleted file mode 100644 index 9c948b367..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Component, OnDestroy, OnInit } from '@angular/core' -import { ActivatedRoute, Router } from '@angular/router' -import { AuthService, Notifier, ServerService } from '@app/core' -import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' -import { VideoChannelUpdate } from '../../../../../shared/models/videos' -import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' -import { Subscription } from 'rxjs' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service' -import { ServerConfig } from '@shared/models' - -@Component({ - selector: 'my-account-video-channel-update', - templateUrl: './my-account-video-channel-edit.component.html', - styleUrls: [ './my-account-video-channel-edit.component.scss' ] -}) -export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelEdit implements OnInit, OnDestroy { - error: string - videoChannelToUpdate: VideoChannel - - private paramsSub: Subscription - private oldSupportField: string - private serverConfig: ServerConfig - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private videoChannelValidatorsService: VideoChannelValidatorsService, - private notifier: Notifier, - private router: Router, - private route: ActivatedRoute, - private videoChannelService: VideoChannelService, - private i18n: I18n, - private serverService: ServerService - ) { - super() - } - - ngOnInit () { - this.serverConfig = this.serverService.getTmpConfig() - this.serverService.getConfig() - .subscribe(config => this.serverConfig = config) - - this.buildForm({ - 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, - description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, - support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT, - bulkVideosSupportUpdate: null - }) - - this.paramsSub = this.route.params.subscribe(routeParams => { - const videoChannelId = routeParams['videoChannelId'] - - this.videoChannelService.getVideoChannel(videoChannelId).subscribe( - videoChannelToUpdate => { - this.videoChannelToUpdate = videoChannelToUpdate - - this.oldSupportField = videoChannelToUpdate.support - - this.form.patchValue({ - 'display-name': videoChannelToUpdate.displayName, - description: videoChannelToUpdate.description, - support: videoChannelToUpdate.support - }) - }, - - err => this.error = err.message - ) - }) - } - - ngOnDestroy () { - if (this.paramsSub) this.paramsSub.unsubscribe() - } - - formValidated () { - this.error = undefined - - const body = this.form.value - const videoChannelUpdate: VideoChannelUpdate = { - displayName: body['display-name'], - description: body.description || null, - support: body.support || null, - bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false - } - - this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe( - () => { - this.authService.refreshUserInformation() - - this.notifier.success( - this.i18n('Video channel {{videoChannelName}} updated.', { videoChannelName: videoChannelUpdate.displayName }) - ) - - this.router.navigate([ '/my-account', 'video-channels' ]) - }, - - err => this.error = err.message - ) - } - - onAvatarChange (formData: FormData) { - this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.name, formData) - .subscribe( - data => { - this.notifier.success(this.i18n('Avatar changed.')) - - this.videoChannelToUpdate.updateAvatar(data.avatar) - }, - - err => this.notifier.error(err.message) - ) - } - - get maxAvatarSize () { - return this.serverConfig.avatar.file.size.max - } - - get avatarExtensions () { - return this.serverConfig.avatar.file.extensions.join(',') - } - - isCreation () { - return false - } - - getFormButtonTitle () { - return this.i18n('Update') - } - - isBulkUpdateVideosDisplayed () { - if (this.oldSupportField === undefined) return false - - return this.oldSupportField !== this.form.value['support'] - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts deleted file mode 100644 index 94037e18f..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { NgModule } from '@angular/core' -import { RouterModule, Routes } from '@angular/router' -import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component' -import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component' -import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component' - -const myAccountVideoChannelsRoutes: Routes = [ - { - path: '', - component: MyAccountVideoChannelsComponent, - data: { - meta: { - title: 'Account video channels' - } - } - }, - { - path: 'create', - component: MyAccountVideoChannelCreateComponent, - data: { - meta: { - title: 'Create new video channel' - } - } - }, - { - path: 'update/:videoChannelId', - component: MyAccountVideoChannelUpdateComponent, - data: { - meta: { - title: 'Update video channel' - } - } - } -] - -@NgModule({ - imports: [ RouterModule.forChild(myAccountVideoChannelsRoutes) ], - exports: [ RouterModule ] -}) -export class MyAccountVideoChannelsRoutingModule {} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html deleted file mode 100644 index b2e8210d3..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html +++ /dev/null @@ -1,35 +0,0 @@ -

My channels

- - -
-
- - Avatar - - -
- -
{{ videoChannel.displayName }}
-
{{ videoChannel.nameWithHost }}
-
- -
{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}
- -
{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}
- -
- - -
- -
- -
-
-
-
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss deleted file mode 100644 index 76fb2cde0..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss +++ /dev/null @@ -1,115 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -.create-button { - @include create-button; -} - -::ng-deep .action-button { - &.action-button-edit { - margin-right: 10px; - } -} - -.video-channel { - @include row-blocks; - padding-bottom: 0; - - img { - @include avatar(80px); - - margin-right: 10px; - } - - .video-channel-info { - flex-grow: 1; - - a.video-channel-names { - @include disable-default-a-behaviour; - - width: fit-content; - display: flex; - align-items: baseline; - color: pvar(--mainForegroundColor); - - .video-channel-display-name { - font-weight: $font-semibold; - font-size: 18px; - } - - .video-channel-name { - font-size: 14px; - color: $grey-actor-name; - margin-left: 5px; - } - - .video-channel-followers { - - } - } - } - - .video-channel-buttons { - margin-top: 10px; - min-width: 190px; - } -} - -.video-channels-header { - text-align: right; - margin: 20px 0 50px; -} - -::ng-deep .chartjs-render-monitor { - position: relative; - top: 1px; -} - -@media screen and (max-width: $small-view) { - .video-channels-header { - text-align: center; - } - - .video-channel { - padding-bottom: 10px; - - .video-channel-info { - padding-bottom: 10px; - text-align: center; - - .video-channel-names { - flex-direction: column; - align-items: center !important; - margin: auto; - - .video-channel-name { - margin-left: 0px !important; - } - } - } - - img { - margin-right: 0; - } - - .video-channel-buttons { - align-self: center; - } - } -} - -@media screen and (min-width: breakpoint(lg)) { - :host-context(.main-col:not(.expanded)) { - .video-channel-buttons { - float: right; - } - } -} - -@media screen and (min-width: $small-view) { - :host-context(.expanded) { - .video-channel-buttons { - float: right; - } - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts deleted file mode 100644 index 9caefe5b1..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { Component, OnInit } from '@angular/core' -import { Notifier } from '@app/core' -import { AuthService } from '../../core/auth' -import { ConfirmService } from '../../core/confirm' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' -import { ScreenService } from '@app/shared/misc/screen.service' -import { User } from '@app/shared' -import { flatMap } from 'rxjs/operators' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { min, minBy, max, maxBy } from 'lodash-es' -import { ChartData } from 'chart.js' - -@Component({ - selector: 'my-account-video-channels', - templateUrl: './my-account-video-channels.component.html', - styleUrls: [ './my-account-video-channels.component.scss' ] -}) -export class MyAccountVideoChannelsComponent implements OnInit { - videoChannels: VideoChannel[] = [] - videoChannelsChartData: ChartData[] - videoChannelsMinimumDailyViews = 0 - videoChannelsMaximumDailyViews: number - - private user: User - - constructor ( - private authService: AuthService, - private notifier: Notifier, - private confirmService: ConfirmService, - private videoChannelService: VideoChannelService, - private screenService: ScreenService, - private i18n: I18n - ) {} - - ngOnInit () { - this.user = this.authService.getUser() - - this.loadVideoChannels() - } - - get isInSmallView () { - return this.screenService.isInSmallView() - } - - get chartOptions () { - return { - legend: { - display: false - }, - scales: { - xAxes: [{ - display: false - }], - yAxes: [{ - display: false, - ticks: { - min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), - max: Math.max(1, this.videoChannelsMaximumDailyViews) - } - }] - }, - layout: { - padding: { - left: 15, - right: 15, - top: 10, - bottom: 0 - } - }, - elements: { - point: { - radius: 0 - } - }, - tooltips: { - mode: 'index', - intersect: false, - custom: function (tooltip: any) { - if (!tooltip) return - // disable displaying the color box - tooltip.displayColors = false - }, - callbacks: { - label: (tooltip: any, data: any) => `${tooltip.value} views` - } - }, - hover: { - mode: 'index', - intersect: false - } - } - } - - async deleteVideoChannel (videoChannel: VideoChannel) { - const res = await this.confirmService.confirmWithInput( - this.i18n( - // tslint:disable - 'Do you really want to delete {{channelDisplayName}}? It will delete {{videosCount}} videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!', - { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name } - ), - this.i18n( - 'Please type the display name of the video channel ({{displayName}}) to confirm', - { displayName: videoChannel.displayName } - ), - videoChannel.displayName, - this.i18n('Delete') - ) - if (res === false) return - - this.videoChannelService.removeVideoChannel(videoChannel) - .subscribe( - () => { - this.loadVideoChannels() - this.notifier.success( - this.i18n('Video channel {{videoChannelName}} deleted.', { videoChannelName: videoChannel.displayName }) - ) - }, - - error => this.notifier.error(error.message) - ) - } - - private loadVideoChannels () { - this.authService.userInformationLoaded - .pipe(flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true))) - .subscribe(res => { - this.videoChannels = res.data - - // chart data - this.videoChannelsChartData = this.videoChannels.map(v => ({ - labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), - datasets: [ - { - label: this.i18n('Views for the day'), - data: v.viewsPerDay.map(day => day.views), - fill: false, - borderColor: "#c6c6c6" - } - ] - } as ChartData)) - - // chart options that depend on chart data: - // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here - this.videoChannelsMinimumDailyViews = min( - this.videoChannels.map(v => minBy( // compute local minimum daily views for each channel, by their "views" attribute - v.viewsPerDay, - day => day.views - ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute - ) - this.videoChannelsMaximumDailyViews = max( - this.videoChannels.map(v => maxBy( // compute local maximum daily views for each channel, by their "views" attribute - v.viewsPerDay, - day => day.views - ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute - ) - }) - } -} diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts deleted file mode 100644 index 87d6b762f..000000000 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NgModule } from '@angular/core' -import { ChartModule } from 'primeng/chart' -import { MyAccountVideoChannelsRoutingModule } from './my-account-video-channels-routing.module' -import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component' -import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component' -import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component' -import { SharedModule } from '@app/shared' - -@NgModule({ - imports: [ - MyAccountVideoChannelsRoutingModule, - SharedModule, - ChartModule - ], - - declarations: [ - MyAccountVideoChannelsComponent, - MyAccountVideoChannelCreateComponent, - MyAccountVideoChannelUpdateComponent - ], - - exports: [], - providers: [] -}) -export class MyAccountVideoChannelsModule { } diff --git a/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.ts b/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.ts index 4452154eb..42ddb0ee2 100644 --- a/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.ts +++ b/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.ts @@ -1,9 +1,8 @@ -import { Component, OnInit } from '@angular/core' -import { RestPagination, RestTable } from '@app/shared' import { SortMeta } from 'primeng/api' -import { Notifier } from '@app/core' -import { VideoImport, VideoImportState } from '../../../../../shared/models/videos' -import { VideoImportService } from '@app/shared/video-import' +import { Component, OnInit } from '@angular/core' +import { Notifier, RestPagination, RestTable } from '@app/core' +import { VideoImportService } from '@app/shared/shared-main' +import { VideoImport, VideoImportState } from '@shared/models' @Component({ selector: 'my-account-video-imports', diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts index e47e5f980..e72ae2366 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts @@ -1,14 +1,13 @@ import { Component, OnInit } from '@angular/core' import { Router } from '@angular/router' import { AuthService, Notifier, ServerService } from '@app/core' -import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit' +import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms' +import { VideoPlaylistService } from '@app/shared/shared-video-playlist' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { VideoPlaylistValidatorsService } from '@app/shared' import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model' -import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' -import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' +import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit' +import { populateAsyncUserVideoChannels } from '@app/helpers' @Component({ selector: 'my-account-video-playlist-create', diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts index e94188786..7ae8de75e 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts @@ -1,6 +1,6 @@ -import { FormReactive } from '@app/shared' -import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' +import { FormReactive } from '@app/shared/shared-forms' import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models' +import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' export abstract class MyAccountVideoPlaylistEdit extends FormReactive { // Declare it here to avoid errors in create template diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.ts index 366640618..0add81c38 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.ts @@ -1,16 +1,9 @@ -import { Component, OnDestroy, OnInit } from '@angular/core' -import { Notifier, ServerService } from '@app/core' -import { AuthService } from '../../core/auth' -import { ConfirmService } from '../../core/confirm' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' import { Subject, Subscription } from 'rxjs' -import { ActivatedRoute } from '@angular/router' -import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' -import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { ScreenService } from '@app/shared/misc/screen.service' import { CdkDragDrop } from '@angular/cdk/drag-drop' -import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { ActivatedRoute } from '@angular/router' +import { ComponentPagination, Notifier, ScreenService } from '@app/core' +import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' @Component({ selector: 'my-account-video-playlist-elements', @@ -33,12 +26,8 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro private paramsSub: Subscription constructor ( - private authService: AuthService, - private serverService: ServerService, private notifier: Notifier, - private confirmService: ConfirmService, private route: ActivatedRoute, - private i18n: I18n, private screenService: ScreenService, private videoPlaylistService: VideoPlaylistService ) {} diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts index 2f85cdd96..6787fb757 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts @@ -1,16 +1,14 @@ +import { forkJoin, Subscription } from 'rxjs' +import { map, switchMap } from 'rxjs/operators' import { Component, OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' import { AuthService, Notifier, ServerService } from '@app/core' -import { forkJoin, Subscription } from 'rxjs' +import { populateAsyncUserVideoChannels } from '@app/helpers' +import { FormValidatorService, VideoPlaylistValidatorsService } from '@app/shared/shared-forms' +import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' -import { MyAccountVideoPlaylistEdit } from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-edit' -import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' -import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' -import { VideoPlaylistValidatorsService } from '@app/shared' -import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model' -import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' -import { delayWhen, map, switchMap } from 'rxjs/operators' +import { VideoPlaylistUpdate } from '@shared/models' +import { MyAccountVideoPlaylistEdit } from './my-account-video-playlist-edit' @Component({ selector: 'my-account-video-playlist-update', diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts index c6728cc30..ea3bcde4f 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts @@ -1,15 +1,10 @@ +import { Subject } from 'rxjs' +import { debounceTime, flatMap } from 'rxjs/operators' import { Component, OnInit } from '@angular/core' -import { Notifier } from '@app/core' -import { AuthService } from '../../core/auth' -import { ConfirmService } from '../../core/confirm' -import { User } from '@app/shared' -import { flatMap, debounceTime } from 'rxjs/operators' +import { AuthService, ComponentPagination, ConfirmService, Notifier, User } from '@app/core' +import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { I18n } from '@ngx-translate/i18n-polyfill' -import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' -import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' import { VideoPlaylistType } from '@shared/models' -import { Subject } from 'rxjs' @Component({ selector: 'my-account-video-playlists', diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts index 0ec033eaf..3cfe8fb38 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts @@ -1,21 +1,15 @@ import { concat, Observable, Subject } from 'rxjs' -import { tap, toArray, debounceTime } from 'rxjs/operators' -import { Component, ViewChild, OnInit } from '@angular/core' +import { debounceTime, tap, toArray } from 'rxjs/operators' +import { Component, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { immutableAssign } from '@app/shared/misc/utils' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' -import { Notifier, ServerService } from '@app/core' -import { AuthService } from '../../core/auth' -import { ConfirmService } from '../../core/confirm' -import { Video } from '../../shared/video/video.model' -import { VideoService } from '../../shared/video/video.service' +import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService } from '@app/core' +import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' +import { immutableAssign } from '@app/helpers' +import { Video, VideoService } from '@app/shared/shared-main' +import { MiniatureDisplayOptions, OwnerDisplayType, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' import { I18n } from '@ngx-translate/i18n-polyfill' -import { ScreenService } from '@app/shared/misc/screen.service' +import { VideoSortField } from '@shared/models' import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component' -import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/video-miniature.component' -import { SelectionType, VideosSelectionComponent } from '@app/shared/video/videos-selection.component' -import { VideoSortField } from '@app/shared/video/sort-field.type' -import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' @Component({ selector: 'my-account-videos', diff --git a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts index f4e2b5955..18e716a09 100644 --- a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts +++ b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.ts @@ -1,11 +1,9 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' -import { Notifier } from '@app/core' +import { Notifier, UserService } from '@app/core' +import { FormReactive, FormValidatorService, VideoChangeOwnershipValidatorsService } from '@app/shared/shared-forms' +import { Video, VideoOwnershipService } from '@app/shared/shared-main' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { FormReactive, UserService } from '../../../shared/index' -import { Video } from '@app/shared/video/video.model' import { I18n } from '@ngx-translate/i18n-polyfill' -import { FormValidatorService, VideoChangeOwnershipValidatorsService } from '@app/shared' -import { VideoOwnershipService } from '@app/shared/video-ownership' @Component({ selector: 'my-video-change-ownership', diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts index ca447c054..ea4da676a 100644 --- a/client/src/app/+my-account/my-account.component.ts +++ b/client/src/app/+my-account/my-account.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core' import { ServerService } from '@app/core' import { I18n } from '@ngx-translate/i18n-polyfill' -import { TopMenuDropdownParam } from '@app/shared/menu/top-menu-dropdown.component' import { ServerConfig } from '@shared/models' +import { TopMenuDropdownParam } from './top-menu-dropdown.component' @Component({ selector: 'my-my-account', diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 72b9fd9f2..9a11a89ea 100644 --- a/client/src/app/+my-account/my-account.module.ts +++ b/client/src/app/+my-account/my-account.module.ts @@ -1,47 +1,55 @@ -import { NgModule } from '@angular/core' -import { TableModule } from 'primeng/table' import { AutoCompleteModule } from 'primeng/autocomplete' import { InputSwitchModule } from 'primeng/inputswitch' -import { SharedModule } from '../shared' +import { TableModule } from 'primeng/table' +import { DragDropModule } from '@angular/cdk/drag-drop' +import { NgModule } from '@angular/core' +import { SharedGlobalIconModule } from '@app/shared/shared-icons' +import { SharedMainModule } from '@app/shared/shared-main' +import { SharedModerationModule } from '@app/shared/shared-moderation' +import { SharedUserInterfaceSettingsModule } from '@app/shared/shared-user-settings' +import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription/shared-user-subscription.module' +import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' +import { SharedVideoPlaylistModule } from '@app/shared/shared-video-playlist/shared-video-playlist.module' +import { MyAccountBlocklistComponent } from './my-account-blocklist/my-account-blocklist.component' +import { MyAccountServerBlocklistComponent } from './my-account-blocklist/my-account-server-blocklist.component' +import { MyAccountHistoryComponent } from './my-account-history/my-account-history.component' +import { MyAccountNotificationsComponent } from './my-account-notifications/my-account-notifications.component' +import { MyAccountAcceptOwnershipComponent } from './my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component' +import { MyAccountOwnershipComponent } from './my-account-ownership/my-account-ownership.component' import { MyAccountRoutingModule } from './my-account-routing.module' +import { MyAccountChangeEmailComponent } from './my-account-settings/my-account-change-email' import { MyAccountChangePasswordComponent } from './my-account-settings/my-account-change-password/my-account-change-password.component' +import { MyAccountDangerZoneComponent } from './my-account-settings/my-account-danger-zone' +import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' +import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' -import { MyAccountComponent } from './my-account.component' +import { MyAccountSubscriptionsComponent } from './my-account-subscriptions/my-account-subscriptions.component' +import { MyAccountVideoImportsComponent } from './my-account-video-imports/my-account-video-imports.component' +import { MyAccountVideoPlaylistCreateComponent } from './my-account-video-playlists/my-account-video-playlist-create.component' +import { MyAccountVideoPlaylistElementsComponent } from './my-account-video-playlists/my-account-video-playlist-elements.component' +import { MyAccountVideoPlaylistUpdateComponent } from './my-account-video-playlists/my-account-video-playlist-update.component' +import { MyAccountVideoPlaylistsComponent } from './my-account-video-playlists/my-account-video-playlists.component' import { MyAccountVideosComponent } from './my-account-videos/my-account-videos.component' import { VideoChangeOwnershipComponent } from './my-account-videos/video-change-ownership/video-change-ownership.component' -import { MyAccountOwnershipComponent } from './my-account-ownership/my-account-ownership.component' -import { MyAccountAcceptOwnershipComponent } from './my-account-ownership/my-account-accept-ownership/my-account-accept-ownership.component' -import { MyAccountProfileComponent } from '@app/+my-account/my-account-settings/my-account-profile/my-account-profile.component' -import { MyAccountVideoImportsComponent } from '@app/+my-account/my-account-video-imports/my-account-video-imports.component' -import { MyAccountDangerZoneComponent } from '@app/+my-account/my-account-settings/my-account-danger-zone' -import { MyAccountSubscriptionsComponent } from '@app/+my-account/my-account-subscriptions/my-account-subscriptions.component' -import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component' -import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component' -import { MyAccountHistoryComponent } from '@app/+my-account/my-account-history/my-account-history.component' -import { MyAccountNotificationsComponent } from '@app/+my-account/my-account-notifications/my-account-notifications.component' -import { MyAccountNotificationPreferencesComponent } from '@app/+my-account/my-account-settings/my-account-notification-preferences' -import { - MyAccountVideoPlaylistCreateComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component' -import { - MyAccountVideoPlaylistUpdateComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component' -import { MyAccountVideoPlaylistsComponent } from '@app/+my-account/my-account-video-playlists/my-account-video-playlists.component' -import { - MyAccountVideoPlaylistElementsComponent -} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component' -import { DragDropModule } from '@angular/cdk/drag-drop' -import { MyAccountChangeEmailComponent } from '@app/+my-account/my-account-settings/my-account-change-email' +import { MyAccountComponent } from './my-account.component' +import { TopMenuDropdownComponent } from './top-menu-dropdown.component' @NgModule({ imports: [ - TableModule, MyAccountRoutingModule, + AutoCompleteModule, - SharedModule, TableModule, InputSwitchModule, - DragDropModule + DragDropModule, + + SharedMainModule, + SharedModerationModule, + SharedVideoMiniatureModule, + SharedUserSubscriptionModule, + SharedVideoPlaylistModule, + SharedUserInterfaceSettingsModule, + SharedGlobalIconModule ], declarations: [ @@ -68,7 +76,9 @@ import { MyAccountChangeEmailComponent } from '@app/+my-account/my-account-setti MyAccountVideoPlaylistCreateComponent, MyAccountVideoPlaylistUpdateComponent, MyAccountVideoPlaylistsComponent, - MyAccountVideoPlaylistElementsComponent + MyAccountVideoPlaylistElementsComponent, + + TopMenuDropdownComponent ], exports: [ diff --git a/client/src/app/+my-account/shared/actor-avatar-info.component.html b/client/src/app/+my-account/shared/actor-avatar-info.component.html deleted file mode 100644 index d01b9ac7f..000000000 --- a/client/src/app/+my-account/shared/actor-avatar-info.component.html +++ /dev/null @@ -1,24 +0,0 @@ - -
-
- Avatar - -
-
- - - -
-
-
- - -
-
-
{{ actor.displayName }}
-
{{ actor.name }}
-
-
{{ actor.followersCount }} subscribers
-
-
-
\ No newline at end of file diff --git a/client/src/app/+my-account/shared/actor-avatar-info.component.scss b/client/src/app/+my-account/shared/actor-avatar-info.component.scss deleted file mode 100644 index 5a66ecfd2..000000000 --- a/client/src/app/+my-account/shared/actor-avatar-info.component.scss +++ /dev/null @@ -1,71 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -.actor { - display: flex; - - img { - @include avatar(100px); - - margin-right: 15px; - } - - .actor-img-edit-container { - position: relative; - width: 0; - - .actor-img-edit-button { - @include peertube-button-file(21px); - @include button-with-icon(19px); - - margin-top: 10px; - margin-bottom: 5px; - border-radius: 50%; - top: 55px; - right: 45px; - cursor: pointer; - - input { - width: 30px; - height: 30px; - } - - my-global-icon { - right: 7px; - } - } - } - - .actor-info { - justify-content: center; - display: inline-flex; - flex-direction: column; - - .actor-info-names { - display: flex; - align-items: center; - - .actor-info-display-name { - font-size: 20px; - font-weight: $font-bold; - - @media screen and (max-width: $small-view) { - font-size: 16px; - } - } - - .actor-info-username { - margin-left: 7px; - position: relative; - top: 2px; - font-size: 14px; - color: $grey-actor-name; - } - } - - .actor-info-followers { - font-size: 15px; - padding-bottom: .5rem; - } - } -} diff --git a/client/src/app/+my-account/shared/actor-avatar-info.component.ts b/client/src/app/+my-account/shared/actor-avatar-info.component.ts deleted file mode 100644 index 8e4a7a602..000000000 --- a/client/src/app/+my-account/shared/actor-avatar-info.component.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' -import { ServerService } from '../../core/server' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { Account } from '@app/shared/account/account.model' -import { Notifier } from '@app/core' -import { ServerConfig } from '@shared/models' -import { BytesPipe } from 'ngx-pipes' -import { I18n } from '@ngx-translate/i18n-polyfill' - -@Component({ - selector: 'my-actor-avatar-info', - templateUrl: './actor-avatar-info.component.html', - styleUrls: [ './actor-avatar-info.component.scss' ] -}) -export class ActorAvatarInfoComponent implements OnInit { - @ViewChild('avatarfileInput') avatarfileInput: ElementRef - - @Input() actor: VideoChannel | Account - - @Output() avatarChange = new EventEmitter() - - maxSizeText: string - - private serverConfig: ServerConfig - private bytesPipe: BytesPipe - - constructor ( - private serverService: ServerService, - private notifier: Notifier, - private i18n: I18n - ) { - this.bytesPipe = new BytesPipe() - this.maxSizeText = this.i18n('max size') - } - - ngOnInit (): void { - this.serverConfig = this.serverService.getTmpConfig() - this.serverService.getConfig() - .subscribe(config => this.serverConfig = config) - } - - onAvatarChange () { - const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] - if (avatarfile.size > this.maxAvatarSize) { - this.notifier.error('Error', 'This image is too large.') - return - } - - const formData = new FormData() - formData.append('avatarfile', avatarfile) - - this.avatarChange.emit(formData) - } - - get maxAvatarSize () { - return this.serverConfig.avatar.file.size.max - } - - get maxAvatarSizeInBytes () { - return this.bytesPipe.transform(this.maxAvatarSize) - } - - get avatarExtensions () { - return this.serverConfig.avatar.file.extensions.join(', ') - } -} diff --git a/client/src/app/+my-account/top-menu-dropdown.component.html b/client/src/app/+my-account/top-menu-dropdown.component.html new file mode 100644 index 000000000..aeaceb662 --- /dev/null +++ b/client/src/app/+my-account/top-menu-dropdown.component.html @@ -0,0 +1,50 @@ + + + + + diff --git a/client/src/app/+my-account/top-menu-dropdown.component.scss b/client/src/app/+my-account/top-menu-dropdown.component.scss new file mode 100644 index 000000000..84dd7dce3 --- /dev/null +++ b/client/src/app/+my-account/top-menu-dropdown.component.scss @@ -0,0 +1,56 @@ +@import '_variables'; +@import '_mixins'; + +.parent-entry { + span[role=button] { + cursor: pointer; + } + + a { + display: block; + } +} + +::ng-deep .dropdown-toggle::after { + position: relative; + top: 2px; +} + +::ng-deep .dropdown-menu { + margin-top: 0 !important; +} + +.icon { + @include dropdown-with-icon-item; + + top: -1px; +} + +.sub-menu.no-scroll { + overflow-x: hidden; +} + +.modal-body { + .hidden { + display: none; + } + + a { + @include disable-default-a-behaviour; + + color: currentColor; + box-sizing: border-box; + display: block; + font-size: 1.2rem; + padding: 9px 12px; + text-align: initial; + text-transform: unset; + width: 100%; + + &.active { + color: pvar(--mainBackgroundColor) !important; + background-color: pvar(--mainHoverColor); + opacity: .9; + } + } +} diff --git a/client/src/app/+my-account/top-menu-dropdown.component.ts b/client/src/app/+my-account/top-menu-dropdown.component.ts new file mode 100644 index 000000000..5909db0b5 --- /dev/null +++ b/client/src/app/+my-account/top-menu-dropdown.component.ts @@ -0,0 +1,131 @@ +import { Subscription } from 'rxjs' +import { filter, take } from 'rxjs/operators' +import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core' +import { NavigationEnd, Router } from '@angular/router' +import { MenuService, ScreenService } from '@app/core' +import { GlobalIconName } from '@app/shared/shared-icons' +import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap' + +export type TopMenuDropdownParam = { + label: string + routerLink?: string + + children?: { + label: string + routerLink: string + + iconName?: GlobalIconName + }[] +} + +@Component({ + selector: 'my-top-menu-dropdown', + templateUrl: './top-menu-dropdown.component.html', + styleUrls: [ './top-menu-dropdown.component.scss' ] +}) +export class TopMenuDropdownComponent implements OnInit, OnDestroy { + @Input() menuEntries: TopMenuDropdownParam[] = [] + + @ViewChild('modal', { static: true }) modal: NgbModal + + suffixLabels: { [ parentLabel: string ]: string } + hasIcons = false + isModalOpened = false + currentMenuEntryIndex: number + + private openedOnHover = false + private routeSub: Subscription + + constructor ( + private router: Router, + private modalService: NgbModal, + private screen: ScreenService, + private menuService: MenuService + ) { } + + get isInSmallView () { + let marginLeft = 0 + if (this.menuService.isMenuDisplayed) { + marginLeft = this.menuService.menuWidth + } + + return this.screen.isInSmallView(marginLeft) + } + + ngOnInit () { + this.updateChildLabels(window.location.pathname) + + this.routeSub = this.router.events + .pipe(filter(event => event instanceof NavigationEnd)) + .subscribe(() => this.updateChildLabels(window.location.pathname)) + + this.hasIcons = this.menuEntries.some( + e => e.children && e.children.some(c => !!c.iconName) + ) + } + + ngOnDestroy () { + if (this.routeSub) this.routeSub.unsubscribe() + } + + openDropdownOnHover (dropdown: NgbDropdown) { + this.openedOnHover = true + dropdown.open() + + // Menu was closed + dropdown.openChange + .pipe(take(1)) + .subscribe(() => this.openedOnHover = false) + } + + dropdownAnchorClicked (dropdown: NgbDropdown) { + if (this.openedOnHover) { + this.openedOnHover = false + return + } + + return dropdown.toggle() + } + + closeDropdownIfHovered (dropdown: NgbDropdown) { + if (this.openedOnHover === false) return + + dropdown.close() + this.openedOnHover = false + } + + openModal (index: number) { + this.currentMenuEntryIndex = index + this.isModalOpened = true + + this.modalService.open(this.modal, { + centered: true, + beforeDismiss: async () => { + this.onModalDismiss() + return true + } + }) + } + + onModalDismiss () { + this.isModalOpened = false + } + + dismissOtherModals () { + this.modalService.dismissAll() + } + + private updateChildLabels (path: string) { + this.suffixLabels = {} + + for (const entry of this.menuEntries) { + if (!entry.children) continue + + for (const child of entry.children) { + if (path.startsWith(child.routerLink)) { + this.suffixLabels[entry.label] = child.label + } + } + } + } +} -- cgit v1.2.3