diff options
12 files changed, 155 insertions, 13 deletions
diff --git a/client/src/app/+accounts/account-videos/account-videos.component.ts b/client/src/app/+accounts/account-videos/account-videos.component.ts index 6d26a4322..5a99aadce 100644 --- a/client/src/app/+accounts/account-videos/account-videos.component.ts +++ b/client/src/app/+accounts/account-videos/account-videos.component.ts | |||
@@ -29,6 +29,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit, | |||
29 | private accountSub: Subscription | 29 | private accountSub: Subscription |
30 | 30 | ||
31 | constructor ( | 31 | constructor ( |
32 | protected i18n: I18n, | ||
32 | protected router: Router, | 33 | protected router: Router, |
33 | protected serverService: ServerService, | 34 | protected serverService: ServerService, |
34 | protected route: ActivatedRoute, | 35 | protected route: ActivatedRoute, |
@@ -36,7 +37,6 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit, | |||
36 | protected notifier: Notifier, | 37 | protected notifier: Notifier, |
37 | protected confirmService: ConfirmService, | 38 | protected confirmService: ConfirmService, |
38 | protected screenService: ScreenService, | 39 | protected screenService: ScreenService, |
39 | private i18n: I18n, | ||
40 | private accountService: AccountService, | 40 | private accountService: AccountService, |
41 | private videoService: VideoService | 41 | private videoService: VideoService |
42 | ) { | 42 | ) { |
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 73340d21a..13607119e 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 | |||
@@ -27,6 +27,7 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn | |||
27 | videosHistoryEnabled: boolean | 27 | videosHistoryEnabled: boolean |
28 | 28 | ||
29 | constructor ( | 29 | constructor ( |
30 | protected i18n: I18n, | ||
30 | protected router: Router, | 31 | protected router: Router, |
31 | protected serverService: ServerService, | 32 | protected serverService: ServerService, |
32 | protected route: ActivatedRoute, | 33 | protected route: ActivatedRoute, |
@@ -34,7 +35,6 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn | |||
34 | protected userService: UserService, | 35 | protected userService: UserService, |
35 | protected notifier: Notifier, | 36 | protected notifier: Notifier, |
36 | protected screenService: ScreenService, | 37 | protected screenService: ScreenService, |
37 | protected i18n: I18n, | ||
38 | private confirmService: ConfirmService, | 38 | private confirmService: ConfirmService, |
39 | private videoService: VideoService, | 39 | private videoService: VideoService, |
40 | private userHistoryService: UserHistoryService | 40 | private userHistoryService: UserHistoryService |
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts index 5e60b34b4..629fd4450 100644 --- a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts +++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts | |||
@@ -29,6 +29,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On | |||
29 | private videoChannelSub: Subscription | 29 | private videoChannelSub: Subscription |
30 | 30 | ||
31 | constructor ( | 31 | constructor ( |
32 | protected i18n: I18n, | ||
32 | protected router: Router, | 33 | protected router: Router, |
33 | protected serverService: ServerService, | 34 | protected serverService: ServerService, |
34 | protected route: ActivatedRoute, | 35 | protected route: ActivatedRoute, |
@@ -36,7 +37,6 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On | |||
36 | protected notifier: Notifier, | 37 | protected notifier: Notifier, |
37 | protected confirmService: ConfirmService, | 38 | protected confirmService: ConfirmService, |
38 | protected screenService: ScreenService, | 39 | protected screenService: ScreenService, |
39 | private i18n: I18n, | ||
40 | private videoChannelService: VideoChannelService, | 40 | private videoChannelService: VideoChannelService, |
41 | private videoService: VideoService | 41 | private videoService: VideoService |
42 | ) { | 42 | ) { |
diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index 14f48b54b..11cf1bd92 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html | |||
@@ -22,11 +22,18 @@ | |||
22 | myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" | 22 | myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" |
23 | class="videos" | 23 | class="videos" |
24 | > | 24 | > |
25 | <my-video-miniature | 25 | <ng-container *ngFor="let video of videos; trackBy: videoById;"> |
26 | *ngFor="let video of videos; trackBy: videoById" [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" | 26 | <div class="date-title" *ngIf="getCurrentGroupedDateLabel(video)"> |
27 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" | 27 | {{ getCurrentGroupedDateLabel(video) }} |
28 | (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" | 28 | </div> |
29 | > | 29 | |
30 | </my-video-miniature> | 30 | |
31 | <my-video-miniature | ||
32 | [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" | ||
33 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" | ||
34 | (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" | ||
35 | > | ||
36 | </my-video-miniature> | ||
37 | </ng-container> | ||
31 | </div> | 38 | </div> |
32 | </div> | 39 | </div> |
diff --git a/client/src/app/shared/video/abstract-video-list.scss b/client/src/app/shared/video/abstract-video-list.scss index d94596113..98b80fdfd 100644 --- a/client/src/app/shared/video/abstract-video-list.scss +++ b/client/src/app/shared/video/abstract-video-list.scss | |||
@@ -24,6 +24,18 @@ | |||
24 | } | 24 | } |
25 | } | 25 | } |
26 | 26 | ||
27 | .date-title { | ||
28 | font-size: 16px; | ||
29 | font-weight: $font-semibold; | ||
30 | margin-bottom: 20px; | ||
31 | margin-top: -10px; | ||
32 | padding-top: 20px; | ||
33 | |||
34 | &:not(:first-child) { | ||
35 | border-top: 1px solid $separator-border-color; | ||
36 | } | ||
37 | } | ||
38 | |||
27 | .margin-content { | 39 | .margin-content { |
28 | @include adapt-margin-content-width; | 40 | @include adapt-margin-content-width; |
29 | } | 41 | } |
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index fa9d38735..eba05c07d 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts | |||
@@ -11,6 +11,17 @@ import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/vid | |||
11 | import { Syndication } from '@app/shared/video/syndication.model' | 11 | import { Syndication } from '@app/shared/video/syndication.model' |
12 | import { Notifier, ServerService } from '@app/core' | 12 | import { Notifier, ServerService } from '@app/core' |
13 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' | 13 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' |
14 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
15 | import { isThisMonth, isThisWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date' | ||
16 | |||
17 | enum GroupDate { | ||
18 | UNKNOWN = 0, | ||
19 | TODAY = 1, | ||
20 | YESTERDAY = 2, | ||
21 | THIS_WEEK = 3, | ||
22 | THIS_MONTH = 4, | ||
23 | OLDER = 5 | ||
24 | } | ||
14 | 25 | ||
15 | export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook { | 26 | export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook { |
16 | pagination: ComponentPagination = { | 27 | pagination: ComponentPagination = { |
@@ -31,6 +42,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
31 | displayModerationBlock = false | 42 | displayModerationBlock = false |
32 | titleTooltip: string | 43 | titleTooltip: string |
33 | displayVideoActions = true | 44 | displayVideoActions = true |
45 | groupByDate = false | ||
34 | 46 | ||
35 | disabled = false | 47 | disabled = false |
36 | 48 | ||
@@ -50,11 +62,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
50 | protected abstract serverService: ServerService | 62 | protected abstract serverService: ServerService |
51 | protected abstract screenService: ScreenService | 63 | protected abstract screenService: ScreenService |
52 | protected abstract router: Router | 64 | protected abstract router: Router |
65 | protected abstract i18n: I18n | ||
53 | abstract titlePage: string | 66 | abstract titlePage: string |
54 | 67 | ||
55 | private resizeSubscription: Subscription | 68 | private resizeSubscription: Subscription |
56 | private angularState: number | 69 | private angularState: number |
57 | 70 | ||
71 | private groupedDateLabels: { [id in GroupDate]: string } | ||
72 | private groupedDates: { [id: number]: GroupDate } = {} | ||
73 | |||
58 | abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }> | 74 | abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }> |
59 | 75 | ||
60 | abstract generateSyndicationList (): void | 76 | abstract generateSyndicationList (): void |
@@ -64,6 +80,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
64 | } | 80 | } |
65 | 81 | ||
66 | ngOnInit () { | 82 | ngOnInit () { |
83 | this.groupedDateLabels = { | ||
84 | [GroupDate.UNKNOWN]: null, | ||
85 | [GroupDate.TODAY]: this.i18n('Today'), | ||
86 | [GroupDate.YESTERDAY]: this.i18n('Yesterday'), | ||
87 | [GroupDate.THIS_WEEK]: this.i18n('This week'), | ||
88 | [GroupDate.THIS_MONTH]: this.i18n('This month'), | ||
89 | [GroupDate.OLDER]: this.i18n('Older') | ||
90 | } | ||
91 | |||
67 | // Subscribe to route changes | 92 | // Subscribe to route changes |
68 | const routeParams = this.route.snapshot.queryParams | 93 | const routeParams = this.route.snapshot.queryParams |
69 | this.loadRouteParams(routeParams) | 94 | this.loadRouteParams(routeParams) |
@@ -113,6 +138,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
113 | this.pagination.totalItems = totalVideos | 138 | this.pagination.totalItems = totalVideos |
114 | this.videos = this.videos.concat(videos) | 139 | this.videos = this.videos.concat(videos) |
115 | 140 | ||
141 | if (this.groupByDate) this.buildGroupedDateLabels() | ||
142 | |||
116 | this.onMoreVideos() | 143 | this.onMoreVideos() |
117 | }, | 144 | }, |
118 | 145 | ||
@@ -134,6 +161,49 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
134 | this.videos = this.videos.filter(v => v.id !== video.id) | 161 | this.videos = this.videos.filter(v => v.id !== video.id) |
135 | } | 162 | } |
136 | 163 | ||
164 | buildGroupedDateLabels () { | ||
165 | let currentGroupedDate: GroupDate = GroupDate.UNKNOWN | ||
166 | |||
167 | for (const video of this.videos) { | ||
168 | const publishedDate = video.publishedAt | ||
169 | |||
170 | if (currentGroupedDate < GroupDate.TODAY && isToday(publishedDate)) { | ||
171 | currentGroupedDate = GroupDate.TODAY | ||
172 | this.groupedDates[ video.id ] = currentGroupedDate | ||
173 | continue | ||
174 | } | ||
175 | |||
176 | if (currentGroupedDate < GroupDate.YESTERDAY && isYesterday(publishedDate)) { | ||
177 | currentGroupedDate = GroupDate.YESTERDAY | ||
178 | this.groupedDates[ video.id ] = currentGroupedDate | ||
179 | continue | ||
180 | } | ||
181 | |||
182 | if (currentGroupedDate < GroupDate.THIS_WEEK && isThisWeek(publishedDate)) { | ||
183 | currentGroupedDate = GroupDate.THIS_WEEK | ||
184 | this.groupedDates[ video.id ] = currentGroupedDate | ||
185 | continue | ||
186 | } | ||
187 | |||
188 | if (currentGroupedDate < GroupDate.THIS_MONTH && isThisMonth(publishedDate)) { | ||
189 | currentGroupedDate = GroupDate.THIS_MONTH | ||
190 | this.groupedDates[ video.id ] = currentGroupedDate | ||
191 | continue | ||
192 | } | ||
193 | |||
194 | if (currentGroupedDate < GroupDate.OLDER) { | ||
195 | currentGroupedDate = GroupDate.OLDER | ||
196 | this.groupedDates[ video.id ] = currentGroupedDate | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | getCurrentGroupedDateLabel (video: Video) { | ||
202 | if (this.groupByDate === false) return undefined | ||
203 | |||
204 | return this.groupedDateLabels[this.groupedDates[video.id]] | ||
205 | } | ||
206 | |||
137 | // On videos hook for children that want to do something | 207 | // On videos hook for children that want to do something |
138 | protected onMoreVideos () { /* empty */ } | 208 | protected onMoreVideos () { /* empty */ } |
139 | 209 | ||
diff --git a/client/src/app/shared/video/videos-selection.component.ts b/client/src/app/shared/video/videos-selection.component.ts index 955ebca9f..d69f7b70e 100644 --- a/client/src/app/shared/video/videos-selection.component.ts +++ b/client/src/app/shared/video/videos-selection.component.ts | |||
@@ -20,6 +20,7 @@ import { Video } from '@app/shared/video/video.model' | |||
20 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' | 20 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' |
21 | import { VideoSortField } from '@app/shared/video/sort-field.type' | 21 | import { VideoSortField } from '@app/shared/video/sort-field.type' |
22 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | 22 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' |
23 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
23 | 24 | ||
24 | export type SelectionType = { [ id: number ]: boolean } | 25 | export type SelectionType = { [ id: number ]: boolean } |
25 | 26 | ||
@@ -44,6 +45,7 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni | |||
44 | globalButtonsTemplate: TemplateRef<any> | 45 | globalButtonsTemplate: TemplateRef<any> |
45 | 46 | ||
46 | constructor ( | 47 | constructor ( |
48 | protected i18n: I18n, | ||
47 | protected router: Router, | 49 | protected router: Router, |
48 | protected route: ActivatedRoute, | 50 | protected route: ActivatedRoute, |
49 | protected notifier: Notifier, | 51 | protected notifier: Notifier, |
diff --git a/client/src/app/videos/video-list/video-local.component.ts b/client/src/app/videos/video-list/video-local.component.ts index 13d4023c2..65543343c 100644 --- a/client/src/app/videos/video-list/video-local.component.ts +++ b/client/src/app/videos/video-list/video-local.component.ts | |||
@@ -22,13 +22,13 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On | |||
22 | filter: VideoFilter = 'local' | 22 | filter: VideoFilter = 'local' |
23 | 23 | ||
24 | constructor ( | 24 | constructor ( |
25 | protected i18n: I18n, | ||
25 | protected router: Router, | 26 | protected router: Router, |
26 | protected serverService: ServerService, | 27 | protected serverService: ServerService, |
27 | protected route: ActivatedRoute, | 28 | protected route: ActivatedRoute, |
28 | protected notifier: Notifier, | 29 | protected notifier: Notifier, |
29 | protected authService: AuthService, | 30 | protected authService: AuthService, |
30 | protected screenService: ScreenService, | 31 | protected screenService: ScreenService, |
31 | private i18n: I18n, | ||
32 | private videoService: VideoService | 32 | private videoService: VideoService |
33 | ) { | 33 | ) { |
34 | super() | 34 | super() |
diff --git a/client/src/app/videos/video-list/video-recently-added.component.ts b/client/src/app/videos/video-list/video-recently-added.component.ts index 80cef813e..f54bade98 100644 --- a/client/src/app/videos/video-list/video-recently-added.component.ts +++ b/client/src/app/videos/video-list/video-recently-added.component.ts | |||
@@ -17,15 +17,16 @@ import { Notifier, ServerService } from '@app/core' | |||
17 | export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { | 17 | export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { |
18 | titlePage: string | 18 | titlePage: string |
19 | sort: VideoSortField = '-publishedAt' | 19 | sort: VideoSortField = '-publishedAt' |
20 | groupByDate = true | ||
20 | 21 | ||
21 | constructor ( | 22 | constructor ( |
23 | protected i18n: I18n, | ||
22 | protected route: ActivatedRoute, | 24 | protected route: ActivatedRoute, |
23 | protected serverService: ServerService, | 25 | protected serverService: ServerService, |
24 | protected router: Router, | 26 | protected router: Router, |
25 | protected notifier: Notifier, | 27 | protected notifier: Notifier, |
26 | protected authService: AuthService, | 28 | protected authService: AuthService, |
27 | protected screenService: ScreenService, | 29 | protected screenService: ScreenService, |
28 | private i18n: I18n, | ||
29 | private videoService: VideoService | 30 | private videoService: VideoService |
30 | ) { | 31 | ) { |
31 | super() | 32 | super() |
diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts index e2ad95bc4..a2c819ebe 100644 --- a/client/src/app/videos/video-list/video-trending.component.ts +++ b/client/src/app/videos/video-list/video-trending.component.ts | |||
@@ -19,13 +19,13 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit, | |||
19 | defaultSort: VideoSortField = '-trending' | 19 | defaultSort: VideoSortField = '-trending' |
20 | 20 | ||
21 | constructor ( | 21 | constructor ( |
22 | protected i18n: I18n, | ||
22 | protected router: Router, | 23 | protected router: Router, |
23 | protected serverService: ServerService, | 24 | protected serverService: ServerService, |
24 | protected route: ActivatedRoute, | 25 | protected route: ActivatedRoute, |
25 | protected notifier: Notifier, | 26 | protected notifier: Notifier, |
26 | protected authService: AuthService, | 27 | protected authService: AuthService, |
27 | protected screenService: ScreenService, | 28 | protected screenService: ScreenService, |
28 | private i18n: I18n, | ||
29 | private videoService: VideoService | 29 | private videoService: VideoService |
30 | ) { | 30 | ) { |
31 | super() | 31 | super() |
diff --git a/client/src/app/videos/video-list/video-user-subscriptions.component.ts b/client/src/app/videos/video-list/video-user-subscriptions.component.ts index 2f0685ccc..3caa371d8 100644 --- a/client/src/app/videos/video-list/video-user-subscriptions.component.ts +++ b/client/src/app/videos/video-list/video-user-subscriptions.component.ts | |||
@@ -19,15 +19,16 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement | |||
19 | titlePage: string | 19 | titlePage: string |
20 | sort = '-publishedAt' as VideoSortField | 20 | sort = '-publishedAt' as VideoSortField |
21 | ownerDisplayType: OwnerDisplayType = 'auto' | 21 | ownerDisplayType: OwnerDisplayType = 'auto' |
22 | groupByDate = true | ||
22 | 23 | ||
23 | constructor ( | 24 | constructor ( |
25 | protected i18n: I18n, | ||
24 | protected router: Router, | 26 | protected router: Router, |
25 | protected serverService: ServerService, | 27 | protected serverService: ServerService, |
26 | protected route: ActivatedRoute, | 28 | protected route: ActivatedRoute, |
27 | protected notifier: Notifier, | 29 | protected notifier: Notifier, |
28 | protected authService: AuthService, | 30 | protected authService: AuthService, |
29 | protected screenService: ScreenService, | 31 | protected screenService: ScreenService, |
30 | private i18n: I18n, | ||
31 | private videoService: VideoService | 32 | private videoService: VideoService |
32 | ) { | 33 | ) { |
33 | super() | 34 | super() |
diff --git a/shared/core-utils/miscs/date.ts b/shared/core-utils/miscs/date.ts new file mode 100644 index 000000000..7f0b4443b --- /dev/null +++ b/shared/core-utils/miscs/date.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | function isToday (d: Date) { | ||
2 | const today = new Date() | ||
3 | |||
4 | return areDatesEqual(d, today) | ||
5 | } | ||
6 | |||
7 | function isYesterday (d: Date) { | ||
8 | const yesterday = new Date() | ||
9 | yesterday.setDate(yesterday.getDate() - 1) | ||
10 | |||
11 | return areDatesEqual(d, yesterday) | ||
12 | } | ||
13 | |||
14 | function isThisWeek (d: Date) { | ||
15 | const minDateOfThisWeek = new Date() | ||
16 | minDateOfThisWeek.setHours(0, 0, 0) | ||
17 | |||
18 | // getDay() -> Sunday - Saturday : 0 - 6 | ||
19 | // We want to start our week on Monday | ||
20 | let dayOfWeek = minDateOfThisWeek.getDay() - 1 | ||
21 | if (dayOfWeek < 0) dayOfWeek = 6 // Sunday | ||
22 | |||
23 | minDateOfThisWeek.setDate(minDateOfThisWeek.getDate() - dayOfWeek) | ||
24 | |||
25 | return d >= minDateOfThisWeek | ||
26 | } | ||
27 | |||
28 | function isThisMonth (d: Date) { | ||
29 | const thisMonth = new Date().getMonth() | ||
30 | |||
31 | return d.getMonth() === thisMonth | ||
32 | } | ||
33 | |||
34 | // --------------------------------------------------------------------------- | ||
35 | |||
36 | export { | ||
37 | isYesterday, | ||
38 | isThisWeek, | ||
39 | isThisMonth, | ||
40 | isToday | ||
41 | } | ||
42 | |||
43 | // --------------------------------------------------------------------------- | ||
44 | |||
45 | function areDatesEqual (d1: Date, d2: Date) { | ||
46 | return d1.getFullYear() === d2.getFullYear() && | ||
47 | d1.getMonth() === d2.getMonth() && | ||
48 | d1.getDate() === d2.getDate() | ||
49 | } | ||