-<div i18n *ngIf="pagination.totalItems === 0">You don't have history yet.</div>
+<div class="top-buttons">
+ <div class="history-switch">
+ <p-inputSwitch [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></p-inputSwitch>
+ <label i18n>History enabled</label>
+ </div>
+
+ <div class="delete-history">
+ <button (click)="deleteHistory()" i18n>Delete history</button>
+ </div>
+</div>
+
+
+<div class="no-history" i18n *ngIf="pagination.totalItems === 0">You don't have videos history yet.</div>
<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" class="videos" #videosElement>
<div *ngFor="let videos of videoPages;" class="videos-page">
@import '_variables';
@import '_mixins';
+.no-history {
+ display: flex;
+ justify-content: center;
+ margin-top: 50px;
+ font-weight: $font-semibold;
+ font-size: 16px;
+}
+
+.top-buttons {
+ margin-bottom: 20px;
+ display: flex;
+
+ .history-switch {
+ display: flex;
+ flex-grow: 1;
+
+ label {
+ margin: 0 0 0 5px;
+ }
+ }
+
+ .delete-history {
+ font-size: 15px;
+
+ button {
+ @include peertube-button;
+ @include grey-button;
+ }
+ }
+}
+
.video {
@include row-blocks;
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'
@Component({
selector: 'my-account-history',
itemsPerPage: 5,
totalItems: null
}
+ videosHistoryEnabled: boolean
protected baseVideoWidth = -1
protected baseVideoHeight = 155
protected router: Router,
protected route: ActivatedRoute,
protected authService: AuthService,
+ protected userService: UserService,
protected notificationsService: NotificationsService,
protected location: Location,
protected screenService: ScreenService,
ngOnInit () {
super.ngOnInit()
+
+ this.videosHistoryEnabled = this.authService.getUser().videosHistoryEnabled
}
ngOnDestroy () {
generateSyndicationList () {
throw new Error('Method not implemented.')
}
+
+ onVideosHistoryChange () {
+ this.userService.updateMyProfile({ videosHistoryEnabled: this.videosHistoryEnabled })
+ .subscribe(
+ () => {
+ const message = this.videosHistoryEnabled === true ?
+ this.i18n('Videos history is enabled') :
+ this.i18n('Videos history is disabled')
+
+ this.notificationsService.success(this.i18n('Success'), message)
+
+ this.authService.refreshUserInformation()
+ },
+
+ err => this.notificationsService.error(this.i18n('Error'), err.message)
+ )
+ }
+
+ async deleteHistory () {
+ const title = this.i18n('Delete videos history')
+ const message = this.i18n('Are you sure you want to delete all your videos history?')
+
+ const res = await this.confirmService.confirm(message, title)
+ if (res !== true) return
+
+ this.userHistoryService.deleteUserVideosHistory()
+ .subscribe(
+ () => {
+ this.notificationsService.success(this.i18n('Success'), this.i18n('Videos history deleted'))
+
+ this.reloadVideos()
+ },
+
+ err => this.notificationsService.error(this.i18n('Error'), err.message)
+ )
+ }
}
import { TableModule } from 'primeng/table'
import { NgModule } from '@angular/core'
import { AutoCompleteModule } from 'primeng/autocomplete'
+import { InputSwitchModule } from 'primeng/inputswitch'
import { SharedModule } from '../shared'
import { MyAccountRoutingModule } from './my-account-routing.module'
import { MyAccountChangePasswordComponent } from './my-account-settings/my-account-change-password/my-account-change-password.component'
MyAccountRoutingModule,
AutoCompleteModule,
SharedModule,
- TableModule
+ TableModule,
+ InputSwitchModule
],
declarations: [
import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
import { UserRight } from '../../../../../shared/models/users/user-right.enum'
+import { User as ServerUserModel } from '../../../../../shared/models/users/user.model'
// Do not use the barrel (dependency loop)
import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role'
-import { User, UserConstructorHash } from '../../shared/users/user.model'
+import { User } from '../../shared/users/user.model'
import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type'
export type TokenOptions = {
ID: 'id',
ROLE: 'role',
EMAIL: 'email',
+ VIDEOS_HISTORY_ENABLED: 'videos-history-enabled',
USERNAME: 'username',
NSFW_POLICY: 'nsfw_policy',
WEBTORRENT_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled',
role: parseInt(peertubeLocalStorage.getItem(this.KEYS.ROLE), 10) as UserRole,
nsfwPolicy: peertubeLocalStorage.getItem(this.KEYS.NSFW_POLICY) as NSFWPolicyType,
webTorrentEnabled: peertubeLocalStorage.getItem(this.KEYS.WEBTORRENT_ENABLED) === 'true',
- autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true'
+ autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true',
+ videosHistoryEnabled: peertubeLocalStorage.getItem(this.KEYS.VIDEOS_HISTORY_ENABLED) === 'true'
},
Tokens.load()
)
peertubeLocalStorage.removeItem(this.KEYS.ROLE)
peertubeLocalStorage.removeItem(this.KEYS.NSFW_POLICY)
peertubeLocalStorage.removeItem(this.KEYS.WEBTORRENT_ENABLED)
+ peertubeLocalStorage.removeItem(this.KEYS.VIDEOS_HISTORY_ENABLED)
peertubeLocalStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO)
peertubeLocalStorage.removeItem(this.KEYS.EMAIL)
Tokens.flush()
}
- constructor (userHash: UserConstructorHash, hashTokens: TokenOptions) {
+ constructor (userHash: Partial<ServerUserModel>, hashTokens: TokenOptions) {
super(userHash)
this.tokens = new Tokens(hashTokens)
}
import { Injectable } from '@angular/core'
-import {
- ActivatedRouteSnapshot,
- CanActivateChild,
- RouterStateSnapshot,
- CanActivate,
- Router
-} from '@angular/router'
+import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'
import { AuthService } from '../auth/auth.service'
-import {
- Account as AccountServerModel,
- hasUserRight,
- User as UserServerModel,
- UserRight,
- UserRole,
- VideoChannel
-} from '../../../../../shared'
+import { hasUserRight, User as UserServerModel, UserRight, UserRole, VideoChannel } from '../../../../../shared'
import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type'
import { Account } from '@app/shared/account/account.model'
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
-export type UserConstructorHash = {
- id: number,
- username: string,
- email: string,
- role: UserRole,
- emailVerified?: boolean,
- videoQuota?: number,
- videoQuotaDaily?: number,
- nsfwPolicy?: NSFWPolicyType,
- webTorrentEnabled?: boolean,
- autoPlayVideo?: boolean,
- createdAt?: Date,
- account?: AccountServerModel,
- videoChannels?: VideoChannel[]
-
- blocked?: boolean
- blockedReason?: string
-}
export class User implements UserServerModel {
id: number
username: string
emailVerified: boolean
role: UserRole
nsfwPolicy: NSFWPolicyType
+
webTorrentEnabled: boolean
autoPlayVideo: boolean
+ videosHistoryEnabled: boolean
+
videoQuota: number
videoQuotaDaily: number
account: Account
blocked: boolean
blockedReason?: string
- constructor (hash: UserConstructorHash) {
+ constructor (hash: Partial<UserServerModel>) {
this.id = hash.id
this.username = hash.username
this.email = hash.email
this.videoQuotaDaily = hash.videoQuotaDaily
this.nsfwPolicy = hash.nsfwPolicy
this.webTorrentEnabled = hash.webTorrentEnabled
+ this.videosHistoryEnabled = hash.videosHistoryEnabled
this.autoPlayVideo = hash.autoPlayVideo
this.createdAt = hash.createdAt
this.blocked = hash.blocked
/deep/ .ui-progressbar {
font-size: 15px !important;
- color: #fff !important;
height: 30px !important;
- line-height: 30px !important;
border-radius: 3px !important;
background-color: rgba(11, 204, 41, 0.16) !important;
text-align: left;
padding-left: 18px;
margin-top: 0 !important;
+ color: #fff !important;
+ line-height: 30px !important;
}
}
@import '_mixins';
@import '~primeng/resources/primeng.css';
-@import '~primeng/resources/themes/bootstrap/theme.css';
+@import '~primeng/resources/themes/nova-light/theme.css';
@mixin glyphicon-light {
font-family: 'Glyphicons Halflings';
// data table customizations
p-table {
- font-size: 15px !important;
-
.ui-table-caption {
- border: none;
+ border: none !important;
+ background-color: #fff !important;
.caption {
height: 40px;
}
}
+ th {
+ background-color: #fff !important;
+ outline: 0;
+ }
+
+ td, th {
+ font-family: $main-fonts;
+ font-size: 15px !important;
+ color: var(--mainForegroundColor) !important;
+ }
+
td {
padding-left: 15px !important;
}
tr {
+ outline: 0;
background-color: var(--mainBackgroundColor) !important;
height: 46px;
&.ui-state-highlight {
- background-color:var(--submenuColor) !important;
- color:var(--mainForegroundColor) !important;
+ background-color: var(--submenuColor) !important;
+
+ td, td > a {
+ color: var(--mainForegroundColor) !important;
+ }
}
}
}
}
+ td {
+ border: none !important;
+ }
+
&:first-child td {
border-top: none !important;
}
}
&.ui-state-highlight {
- background-color:var(--submenuColor) !important;
+ background-color: var(--submenuColor) !important;
.pi {
@extend .glyphicon;
- color: #000;
- font-size: 11px;
- top: 0;
+ color: #000 !important;
+ font-size: 11px !important;
+ top: 0 !important;
&.pi-sort-up {
@extend .glyphicon-triangle-top;
a {
color: #000 !important;
font-weight: $font-semibold !important;
- margin: 0 10px !important;
+ margin: 0 5px !important;
outline: 0 !important;
border-radius: 3px !important;
padding: 5px 2px !important;
height: auto !important;
+ line-height: initial !important;
&.ui-state-active {
&, &:hover, &:active, &:focus {
.ui-datepicker-next {
@extend .glyphicon-chevron-right;
@include glyphicon-light;
+
+ text-align: right;
+
+ .pi.pi-chevron-right {
+ display: none !important;
+ }
}
.ui-datepicker-prev {
@extend .glyphicon-chevron-left;
@include glyphicon-light;
+
+ text-align: left;
+
+ .pi.pi-chevron-left {
+ display: none !important;
+ }
}
}
}
}
+
.ui-chkbox-box {
&.ui-state-active {
border-color: var(--mainColor) !important;
.ui-chkbox-icon {
position: relative;
+ overflow: visible !important;
&:after {
content: '';
position: absolute;
- left: 5px;
+ top: 1px;
+ left: 7px;
width: 5px;
- height: 12px;
+ height: 13px;
opacity: 0;
transform: rotate(45deg) scale(0);
border-right: 2px solid var(--mainBackgroundColor);
transform: rotate(45deg) scale(1);
}
}
-}
\ No newline at end of file
+}
+
+p-inputswitch {
+ .ui-inputswitch-checked .ui-inputswitch-slider {
+ background-color: var(--mainColor) !important;
+ }
+}
emailVerified: this.emailVerified,
nsfwPolicy: this.nsfwPolicy,
webTorrentEnabled: this.webTorrentEnabled,
+ videosHistoryEnabled: this.videosHistoryEnabled,
autoPlayVideo: this.autoPlayVideo,
role: this.role,
roleLabel: USER_ROLE_LABELS[ this.role ],
email: string
emailVerified: boolean
nsfwPolicy: NSFWPolicyType
+
autoPlayVideo: boolean
+ webTorrentEnabled: boolean
+ videosHistoryEnabled: boolean
+
role: UserRole
videoQuota: number
videoQuotaDaily: number