From 1a79b489abca25fbb6811e30156c4f38dc87dd5d Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 06:58:05 -0400 Subject: [PATCH] Added video info dialog File cards and subscription file cards now use video info dialog so that users can see info on each individual video Ellipsis are now added client-side to video titles in file cards --- backend/app.js | 40 ++++++++++++------- package.json | 1 + src/app/app.module.ts | 4 +- .../video-info-dialog.component.html | 28 +++++++++++++ .../video-info-dialog.component.scss | 18 +++++++++ .../video-info-dialog.component.spec.ts | 25 ++++++++++++ .../video-info-dialog.component.ts | 22 ++++++++++ src/app/file-card/file-card.component.css | 8 ++++ src/app/file-card/file-card.component.html | 12 +++--- src/app/file-card/file-card.component.ts | 18 +++++++-- src/app/main/main.component.html | 4 +- .../subscription-file-card.component.html | 1 + .../subscription-file-card.component.ts | 15 +++++-- 13 files changed, 168 insertions(+), 28 deletions(-) create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.html create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.scss create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.ts diff --git a/backend/app.js b/backend/app.js index d616e57..3fdd32c 100644 --- a/backend/app.js +++ b/backend/app.js @@ -84,12 +84,16 @@ app.use(bodyParser.json()); // objects -function File(id, title, thumbnailURL, isAudio, duration) { +function File(id, title, thumbnailURL, isAudio, duration, url = null, uploader = null, size = null, path = null) { this.id = id; this.title = title; this.thumbnailURL = thumbnailURL; this.isAudio = isAudio; this.duration = duration; + this.url = url; + this.uploader = uploader; + this.size = size; + this.path = path; } // actual functions @@ -951,20 +955,21 @@ app.post('/api/getMp3s', function(req, res) { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(audioFolderPath.length, file.length); + + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp3(id); if (!jsonobj) continue; var title = jsonobj.title; - - if (title.length > 14) // edits title if it's too long - { - title = title.substring(0,12) + "..."; - } + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; var isaudio = true; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); mp3s.push(file_obj); } @@ -984,20 +989,21 @@ app.post('/api/getMp4s', function(req, res) { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(videoFolderPath.length, file.length); + + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp4(id); if (!jsonobj) continue; var title = jsonobj.title; - - if (title.length > 14) // edits title if it's too long - { - title = title.substring(0,12) + "..."; - } + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); mp4s.push(file_obj); } @@ -1101,6 +1107,8 @@ app.post('/api/getSubscription', async (req, res) => { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(appended_base_path.length, file.length); + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp4(id, appended_base_path); if (!jsonobj) continue; @@ -1108,8 +1116,12 @@ app.post('/api/getSubscription', async (req, res) => { var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; + var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); parsed_files.push(file_obj); } diff --git a/package.json b/package.json index dcbef0f..64c1aec 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@locl/core": "0.0.1-beta.2", "core-js": "^2.4.1", "file-saver": "^2.0.2", + "filesize": "^6.1.0", "ng-lazyload-image": "^7.0.1", "ng4-configure": "^0.1.7", "ngx-content-loading": "^0.1.3", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a430fff..e88d6fb 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -49,6 +49,7 @@ import { SettingsComponent } from './settings/settings.component'; import es from '@angular/common/locales/es'; import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component'; +import { VideoInfoDialogComponent } from './dialogs/video-info-dialog/video-info-dialog.component'; registerLocaleData(es, 'es'); export function isVisible({ event, element, scrollContainer, offset }: IsVisibleProps) { @@ -70,7 +71,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible SubscriptionFileCardComponent, SubscriptionInfoDialogComponent, SettingsComponent, - AboutDialogComponent + AboutDialogComponent, + VideoInfoDialogComponent ], imports: [ BrowserModule, diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.html b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html new file mode 100644 index 0000000..234b77d --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html @@ -0,0 +1,28 @@ +

{{file.title}}

+ + +
+
Name: 
+
{{file.title}}
+
+
+
URL: 
+ +
+
+
Uploader: 
+
{{file.uploader ? file.uploader : 'N/A'}}
+
+
+
File size: 
+
{{filesize(file.size)}}
+
+
+
Path: 
+
{{file.path}}
+
+
+ + + + \ No newline at end of file diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss b/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss new file mode 100644 index 0000000..6e7c4f9 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss @@ -0,0 +1,18 @@ +.info-item { + margin-bottom: 12px; + width: 100%; +} + +.info-item-value { + font-size: 13px; + display: inline-block; + width: 70%; +} + +.spacer {flex: 1 1 auto;} + +.info-item-label { + display: inline-block; + width: 30%; + vertical-align: top; +} diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts b/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts new file mode 100644 index 0000000..126ea43 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VideoInfoDialogComponent } from './video-info-dialog.component'; + +describe('VideoInfoDialogComponent', () => { + let component: VideoInfoDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ VideoInfoDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VideoInfoDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts b/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts new file mode 100644 index 0000000..4bfc8e3 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import filesize from 'filesize'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-video-info-dialog', + templateUrl: './video-info-dialog.component.html', + styleUrls: ['./video-info-dialog.component.scss'] +}) +export class VideoInfoDialogComponent implements OnInit { + file: any; + filesize; + constructor(@Inject(MAT_DIALOG_DATA) public data: any) { } + + ngOnInit(): void { + this.filesize = filesize; + if (this.data) { + this.file = this.data.file; + } + } + +} diff --git a/src/app/file-card/file-card.component.css b/src/app/file-card/file-card.component.css index 342885f..a581bca 100644 --- a/src/app/file-card/file-card.component.css +++ b/src/app/file-card/file-card.component.css @@ -51,6 +51,14 @@ -webkit-line-clamp: 2; } +.file-link { + width: 80%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; +} + @media (max-width: 576px){ .example-card { diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index 1c796c5..fd4317d 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -1,8 +1,9 @@
- {{title}} -
+
+ {{title}} +
ID: {{name}}
Count: {{count}}
@@ -15,10 +16,11 @@
- - + + + - +
diff --git a/src/app/file-card/file-card.component.ts b/src/app/file-card/file-card.component.ts index 770976e..1c896c2 100644 --- a/src/app/file-card/file-card.component.ts +++ b/src/app/file-card/file-card.component.ts @@ -5,6 +5,8 @@ import {EventEmitter} from '@angular/core'; import { MainComponent } from 'app/main/main.component'; import { Subject, Observable } from 'rxjs'; import 'rxjs/add/observable/merge'; +import { MatDialog } from '@angular/material/dialog'; +import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component'; @Component({ selector: 'app-file-card', @@ -12,7 +14,7 @@ import 'rxjs/add/observable/merge'; styleUrls: ['./file-card.component.css'] }) export class FileCardComponent implements OnInit { - + @Input() file: any; @Input() title: string; @Input() length: string; @Input() name: string; @@ -29,8 +31,10 @@ export class FileCardComponent implements OnInit { scrollSubject; scrollAndLoad; - constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent) { - this.scrollSubject = new Subject(); + constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent, + private dialog: MatDialog) { + + this.scrollSubject = new Subject(); this.scrollAndLoad = Observable.merge( Observable.fromEvent(window, 'scroll'), this.scrollSubject @@ -57,6 +61,14 @@ export class FileCardComponent implements OnInit { } + openSubscriptionInfoDialog() { + const dialogRef = this.dialog.open(VideoInfoDialogComponent, { + data: { + file: this.file, + } + }); + } + onImgError(event) { this.image_errored = true; } diff --git a/src/app/main/main.component.html b/src/app/main/main.component.html index dc11d79..982a917 100644 --- a/src/app/main/main.component.html +++ b/src/app/main/main.component.html @@ -203,7 +203,7 @@
- @@ -244,7 +244,7 @@
- diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.html b/src/app/subscription/subscription-file-card/subscription-file-card.component.html index a2972a9..81897db 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.html +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.html @@ -4,6 +4,7 @@
+ diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts index c2c23e2..6c9b3b7 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts @@ -3,6 +3,8 @@ import { Observable, Subject } from 'rxjs'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Router } from '@angular/router'; import { PostsService } from 'app/posts.services'; +import { MatDialog } from '@angular/material/dialog'; +import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component'; @Component({ selector: 'app-subscription-file-card', @@ -25,7 +27,7 @@ export class SubscriptionFileCardComponent implements OnInit { @Output() goToFileEmit = new EventEmitter(); @Output() reloadSubscription = new EventEmitter(); - constructor(private snackBar: MatSnackBar, private postsService: PostsService) { + constructor(private snackBar: MatSnackBar, private postsService: PostsService, private dialog: MatDialog) { this.scrollSubject = new Subject(); this.scrollAndLoad = Observable.merge( Observable.fromEvent(window, 'scroll'), @@ -55,6 +57,14 @@ export class SubscriptionFileCardComponent implements OnInit { this.goToFileEmit.emit(this.file.id); } + openSubscriptionInfoDialog() { + const dialogRef = this.dialog.open(VideoInfoDialogComponent, { + data: { + file: this.file, + } + }); + } + deleteAndRedownload() { this.postsService.deleteSubscriptionFile(this.sub, this.file.id, false).subscribe(res => { this.reloadSubscription.emit(true); @@ -77,8 +87,7 @@ export class SubscriptionFileCardComponent implements OnInit { } -function fancyTimeFormat(time) -{ +function fancyTimeFormat(time) { // Hours, minutes and seconds const hrs = ~~(time / 3600); const mins = ~~((time % 3600) / 60);