*ngIf="playlist" [playlist]="playlist" [toManage]="false" [displayChannel]="true"
[displayDescription]="true" [displayPrivacy]="true"
></my-video-playlist-miniature>
+
+ <div class="playlist-buttons">
+ <button (click)="showShareModal()" class="action-button share-button">
+ <my-global-icon iconName="share" aria-hidden="true"></my-global-icon>
+ <span class="icon-text" i18n>Share</span>
+ </button>
+
+ <my-action-dropdown
+ *ngIf="isRegularPlaylist(playlist)"
+ [entry]="playlist" [actions]="playlistActions" label="More"
+ ></my-action-dropdown>
+ </div>
+
</div>
<div class="playlist-elements col-xs-12 col-md-7 col-xl-9">
- <div i18n class="no-results" *ngIf="pagination.totalItems === 0">No videos in this playlist.</div>
+ <div class="no-results" *ngIf="pagination.totalItems === 0">
+ <div i18n>No videos in this playlist.</div>
+
+ <div i18n>
+ Browse videos on PeerTube to add them in your playlist.
+ </div>
+
+ <div i18n>
+ See the <a target="_blank" href="https://docs.joinpeertube.org/#/use-library?id=playlist">documentation</a> for more information.
+ </div>
+ </div>
<div
class="videos" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()"
</div>
</div>
</div>
+
+<my-video-share #videoShareModal [playlist]="playlist"></my-video-share>
padding: 10px;
display: flex;
+ flex-direction: column;
justify-content: center;
+ align-items: center;
/* fix ellipsis dots background color */
::ng-deep .miniature-name::after {
}
}
+.playlist-buttons {
+ display:flex;
+ margin: 30px 0 10px 0;
+
+ .share-button {
+ @include peertube-button;
+ @include button-with-icon(17px, 3px, -1px);
+ @include grey-button;
+ @include apply-svg-color(pvar(--actionButtonColor));
+
+ margin-right: 10px;
+ }
+}
+
// Thanks Angular CDK <3 https://material.angular.io/cdk/drag-drop/examples
.cdk-drag-preview {
box-sizing: border-box;
import { Subject, Subscription } from 'rxjs'
import { CdkDragDrop } from '@angular/cdk/drag-drop'
-import { Component, OnDestroy, OnInit } from '@angular/core'
-import { ActivatedRoute } from '@angular/router'
-import { ComponentPagination, Notifier, ScreenService } from '@app/core'
+import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { ActivatedRoute, Router } from '@angular/router'
+import { ComponentPagination, ConfirmService, Notifier, ScreenService } from '@app/core'
+import { DropdownAction } from '@app/shared/shared-main'
+import { VideoShareComponent } from '@app/shared/shared-share-modal'
import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { VideoPlaylistType } from '@shared/models'
@Component({
selector: 'my-account-video-playlist-elements',
styleUrls: [ './my-account-video-playlist-elements.component.scss' ]
})
export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestroy {
+ @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
+
playlistElements: VideoPlaylistElement[] = []
playlist: VideoPlaylist
+ playlistActions: DropdownAction<VideoPlaylist>[][] = []
+
pagination: ComponentPagination = {
currentPage: 1,
itemsPerPage: 10,
constructor (
private notifier: Notifier,
+ private i18n: I18n,
+ private router: Router,
+ private confirmService: ConfirmService,
private route: ActivatedRoute,
private screenService: ScreenService,
private videoPlaylistService: VideoPlaylistService
) {}
ngOnInit () {
+ this.playlistActions = [
+ [
+ {
+ label: this.i18n('Update playlist'),
+ iconName: 'edit',
+ linkBuilder: playlist => [ '/my-account', 'video-playlists', 'update', playlist.uuid ]
+ },
+ {
+ label: this.i18n('Delete playlist'),
+ iconName: 'delete',
+ handler: playlist => this.deleteVideoPlaylist(playlist)
+ }
+ ]
+ ]
+
this.paramsSub = this.route.params.subscribe(routeParams => {
this.videoPlaylistId = routeParams[ 'videoPlaylistId' ]
this.loadElements()
return elem.id
}
+ isRegularPlaylist (playlist: VideoPlaylist) {
+ return playlist?.type.id === VideoPlaylistType.REGULAR
+ }
+
+ showShareModal () {
+ this.videoShareModal.show()
+ }
+
+ async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) {
+ const res = await this.confirmService.confirm(
+ this.i18n(
+ 'Do you really want to delete {{playlistDisplayName}}?',
+ { playlistDisplayName: videoPlaylist.displayName }
+ ),
+ this.i18n('Delete')
+ )
+ if (res === false) return
+
+ this.videoPlaylistService.removeVideoPlaylist(videoPlaylist)
+ .subscribe(
+ () => {
+ this.router.navigate([ '/my-account', 'video-playlists' ])
+
+ this.notifier.success(
+ this.i18n('Playlist {{playlistDisplayName}} deleted.', { playlistDisplayName: videoPlaylist.displayName })
+ )
+ },
+
+ error => this.notifier.error(error.message)
+ )
+ }
+
/**
* Returns null to not have drag and drop delay.
* In small views, where elements are about 100% wide,
import { SharedGlobalIconModule } from '@app/shared/shared-icons'
import { SharedMainModule } from '@app/shared/shared-main'
import { SharedModerationModule } from '@app/shared/shared-moderation'
+import { SharedShareModal } from '@app/shared/shared-share-modal'
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'
SharedVideoPlaylistModule,
SharedUserInterfaceSettingsModule,
SharedGlobalIconModule,
- SharedAbuseListModule
+ SharedAbuseListModule,
+ SharedShareModal
],
declarations: [
<my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
<span class="icon-text d-none d-sm-inline" i18n>DOWNLOAD</span>
</button>
-
+
<my-video-download #videoDownloadModal></my-video-download>
</ng-container>
+
<ng-container *ngIf="isUserLoggedIn()">
<my-video-actions-dropdown
placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions"
import { HooksService } from '@app/core/plugins/hooks.service'
import { RedirectService } from '@app/core/routing/redirect.service'
import { isXPercentInViewport, scrollToTop } from '@app/helpers'
-import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main'
+import { VideoShareComponent } from '@app/shared/shared-share-modal'
import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
+import { VideoDownloadComponent } from '@app/shared/shared-video-miniature'
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { MetaService } from '@ngx-meta/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { ServerConfig, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage'
import {
} from '../../../assets/player/peertube-player-manager'
import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils'
import { environment } from '../../../environments/environment'
-import { VideoShareComponent } from './modal/video-share.component'
import { VideoSupportComponent } from './modal/video-support.component'
import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
-import { VideoDownloadComponent } from '@app/shared/shared-video-miniature'
@Component({
selector: 'my-video-watch',
-import { QRCodeModule } from 'angularx-qrcode'
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 { SharedModerationModule } from '@app/shared/shared-moderation'
+import { SharedShareModal } from '@app/shared/shared-share-modal'
import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription'
import { SharedVideoCommentModule } from '@app/shared/shared-video-comment'
import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature'
import { SharedVideoPlaylistModule } from '@app/shared/shared-video-playlist'
-import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { VideoCommentService } from '../../shared/shared-video-comment/video-comment.service'
import { VideoCommentAddComponent } from './comment/video-comment-add.component'
import { VideoCommentComponent } from './comment/video-comment.component'
import { VideoCommentsComponent } from './comment/video-comments.component'
-import { VideoShareComponent } from './modal/video-share.component'
import { VideoSupportComponent } from './modal/video-support.component'
import { RecommendationsModule } from './recommendations/recommendations.module'
import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive'
@NgModule({
imports: [
VideoWatchRoutingModule,
- NgbTooltipModule,
- QRCodeModule,
RecommendationsModule,
SharedMainModule,
SharedUserSubscriptionModule,
SharedModerationModule,
SharedGlobalIconModule,
- SharedVideoCommentModule
+ SharedVideoCommentModule,
+ SharedShareModal
],
declarations: [
VideoWatchComponent,
VideoWatchPlaylistComponent,
- VideoShareComponent,
VideoSupportComponent,
VideoCommentsComponent,
VideoCommentAddComponent,
--- /dev/null
+export * from './video-share.component'
+
+export * from './shared-share-modal.module'
--- /dev/null
+import { QRCodeModule } from 'angularx-qrcode'
+import { NgModule } from '@angular/core'
+import { SharedFormModule } from '../shared-forms'
+import { SharedGlobalIconModule } from '../shared-icons'
+import { SharedMainModule } from '../shared-main/shared-main.module'
+import { VideoShareComponent } from './video-share.component'
+
+@NgModule({
+ imports: [
+ QRCodeModule,
+
+ SharedMainModule,
+ SharedFormModule,
+ SharedGlobalIconModule
+ ],
+
+ declarations: [
+ VideoShareComponent
+ ],
+
+ exports: [
+ VideoShareComponent
+ ],
+
+ providers: [ ]
+})
+export class SharedShareModal { }
<div class="modal-body">
- <div class="playlist" *ngIf="hasPlaylist()">
- <div class="title-page title-page-single" i18n>Share the playlist</div>
+ <div class="playlist" *ngIf="playlist">
+ <div class="title-page title-page-single" i18n *ngIf="video">Share the playlist</div>
<div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activePlaylistId">
<div class="filters">
- <div class="form-group">
+ <div class="form-group" *ngIf="video">
<my-peertube-checkbox inputName="includeVideoInPlaylist" [(ngModel)]="includeVideoInPlaylist" i18n-labelText
labelText="Share the playlist at this video position"></my-peertube-checkbox>
</div>
</div>
- <div class="video">
- <div class="title-page title-page-single" *ngIf="hasPlaylist()" i18n>Share the video</div>
+ <div class="video" *ngIf="video">
+ <div class="title-page title-page-single" *ngIf="playlist" i18n>Share the video</div>
<div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activeVideoId">
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
-import { buildVideoOrPlaylistEmbed, buildVideoLink, buildPlaylistLink } from '../../../../assets/player/utils'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
-import { VideoCaption } from '@shared/models'
import { VideoDetails } from '@app/shared/shared-main'
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { VideoCaption } from '@shared/models'
+import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from '../../../assets/player/utils'
type Customizations = {
startAtCheckbox: boolean
show (currentVideoTimestamp?: number, currentPlaylistPosition?: number) {
let subtitle: string
- if (this.videoCaptions.length !== 0) {
+ if (this.videoCaptions && this.videoCaptions.length !== 0) {
subtitle = this.videoCaptions[0].language.id
}
startAt: currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0,
stopAtCheckbox: false,
- stopAt: this.video.duration,
+ stopAt: this.video?.duration,
subtitleCheckbox: false,
subtitle,
return this.activeVideoId === 'embed'
}
- hasPlaylist () {
- return !!this.playlist
- }
-
private getPlaylistOptions (baseUrl?: string) {
return {
baseUrl,
max-height: 500px;
display: flex;
+ flex-direction: column;
align-items: center;
justify-content: center;
font-size: 16px;