This commit is contained in:
Peter Maquiran
2024-02-23 12:39:59 +01:00
29 changed files with 1742 additions and 877 deletions
+82 -2
View File
@@ -49,7 +49,12 @@
"@capacitor/share": "^4.1.0", "@capacitor/share": "^4.1.0",
"@capacitor/storage": "^1.2.5", "@capacitor/storage": "^1.2.5",
"@capawesome/capacitor-file-picker": "^5.3.0", "@capawesome/capacitor-file-picker": "^5.3.0",
<<<<<<< HEAD
"@capawesome/capacitor-screen-orientation": "^5.0.1", "@capawesome/capacitor-screen-orientation": "^5.0.1",
=======
"@ffmpeg/core": "^0.12.6",
"@ffmpeg/ffmpeg": "^0.12.10",
>>>>>>> feature/upload-streaming-videos
"@fortawesome/angular-fontawesome": "^0.9.0", "@fortawesome/angular-fontawesome": "^0.9.0",
"@fortawesome/fontawesome-free": "^5.15.3", "@fortawesome/fontawesome-free": "^5.15.3",
"@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/fontawesome-svg-core": "^1.2.35",
@@ -154,6 +159,7 @@
"lite-server": "^2.6.1", "lite-server": "^2.6.1",
"minisearch": "^6.0.1", "minisearch": "^6.0.1",
"moment": "^2.29.3", "moment": "^2.29.3",
"mux.js": "^6.3.0",
"neverthrow": "^6.1.0", "neverthrow": "^6.1.0",
"ng-lazyload-image": "^9.1.2", "ng-lazyload-image": "^9.1.2",
"ng2-pdf-viewer": "^3.0.8", "ng2-pdf-viewer": "^3.0.8",
@@ -3616,7 +3622,6 @@
"version": "7.14.8", "version": "7.14.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
"integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
"dev": true,
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
}, },
@@ -4022,6 +4027,7 @@
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/@capawesome/capacitor-file-picker/-/capacitor-file-picker-5.3.0.tgz", "resolved": "https://registry.npmjs.org/@capawesome/capacitor-file-picker/-/capacitor-file-picker-5.3.0.tgz",
"integrity": "sha512-r+cfD+9FCBXMYtckSovgi7WoMWT5cxzNDaH3SDNuiORiyQklOl+7DExfhW00p1DqsDR+f50nADk/NBb4IsGVYg==", "integrity": "sha512-r+cfD+9FCBXMYtckSovgi7WoMWT5cxzNDaH3SDNuiORiyQklOl+7DExfhW00p1DqsDR+f50nADk/NBb4IsGVYg==",
<<<<<<< HEAD
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -4040,6 +4046,8 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@capawesome/capacitor-screen-orientation/-/capacitor-screen-orientation-5.0.1.tgz", "resolved": "https://registry.npmjs.org/@capawesome/capacitor-screen-orientation/-/capacitor-screen-orientation-5.0.1.tgz",
"integrity": "sha512-IaF7HjlxS1EXjUNCa8Ztu9EpxsplAYsNcDUHVX2x3B+KRqB0f7DQYi96cnKYeWpMt9JhrLPXc8XGRP4suU4NYw==", "integrity": "sha512-IaF7HjlxS1EXjUNCa8Ztu9EpxsplAYsNcDUHVX2x3B+KRqB0f7DQYi96cnKYeWpMt9JhrLPXc8XGRP4suU4NYw==",
=======
>>>>>>> feature/upload-streaming-videos
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -4250,6 +4258,33 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/@ffmpeg/core": {
"version": "0.12.6",
"resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.12.6.tgz",
"integrity": "sha512-PrjWBTfGn2WVn9T7wGnzfFwChbqWeZc7tM9vvJZVRadYFUDakfzy7W0LpYC0cvvK0xT82qlBsk38lQhJ/Hps5A==",
"engines": {
"node": ">=16.x"
}
},
"node_modules/@ffmpeg/ffmpeg": {
"version": "0.12.10",
"resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.12.10.tgz",
"integrity": "sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==",
"dependencies": {
"@ffmpeg/types": "^0.12.2"
},
"engines": {
"node": ">=18.x"
}
},
"node_modules/@ffmpeg/types": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@ffmpeg/types/-/types-0.12.2.tgz",
"integrity": "sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA==",
"engines": {
"node": ">=16.x"
}
},
"node_modules/@firebase/analytics": { "node_modules/@firebase/analytics": {
"version": "0.6.18", "version": "0.6.18",
"resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.6.18.tgz", "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.6.18.tgz",
@@ -26836,6 +26871,22 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
}, },
"node_modules/mux.js": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.3.0.tgz",
"integrity": "sha512-/QTkbSAP2+w1nxV+qTcumSDN5PA98P0tjrADijIzQHe85oBK3Akhy9AHlH0ne/GombLMz1rLyvVsmrgRxoPDrQ==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"global": "^4.4.0"
},
"bin": {
"muxjs-transmux": "bin/transmux.js"
},
"engines": {
"node": ">=8",
"npm": ">=5"
}
},
"node_modules/nan": { "node_modules/nan": {
"version": "2.17.0", "version": "2.17.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
@@ -46204,7 +46255,6 @@
"version": "7.14.8", "version": "7.14.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
"integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
"dev": true,
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
@@ -46516,12 +46566,15 @@
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/@capawesome/capacitor-file-picker/-/capacitor-file-picker-5.3.0.tgz", "resolved": "https://registry.npmjs.org/@capawesome/capacitor-file-picker/-/capacitor-file-picker-5.3.0.tgz",
"integrity": "sha512-r+cfD+9FCBXMYtckSovgi7WoMWT5cxzNDaH3SDNuiORiyQklOl+7DExfhW00p1DqsDR+f50nADk/NBb4IsGVYg==", "integrity": "sha512-r+cfD+9FCBXMYtckSovgi7WoMWT5cxzNDaH3SDNuiORiyQklOl+7DExfhW00p1DqsDR+f50nADk/NBb4IsGVYg==",
<<<<<<< HEAD
"requires": {} "requires": {}
}, },
"@capawesome/capacitor-screen-orientation": { "@capawesome/capacitor-screen-orientation": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@capawesome/capacitor-screen-orientation/-/capacitor-screen-orientation-5.0.1.tgz", "resolved": "https://registry.npmjs.org/@capawesome/capacitor-screen-orientation/-/capacitor-screen-orientation-5.0.1.tgz",
"integrity": "sha512-IaF7HjlxS1EXjUNCa8Ztu9EpxsplAYsNcDUHVX2x3B+KRqB0f7DQYi96cnKYeWpMt9JhrLPXc8XGRP4suU4NYw==", "integrity": "sha512-IaF7HjlxS1EXjUNCa8Ztu9EpxsplAYsNcDUHVX2x3B+KRqB0f7DQYi96cnKYeWpMt9JhrLPXc8XGRP4suU4NYw==",
=======
>>>>>>> feature/upload-streaming-videos
"requires": {} "requires": {}
}, },
"@cnakazawa/watch": { "@cnakazawa/watch": {
@@ -46684,6 +46737,24 @@
"integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==",
"dev": true "dev": true
}, },
"@ffmpeg/core": {
"version": "0.12.6",
"resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.12.6.tgz",
"integrity": "sha512-PrjWBTfGn2WVn9T7wGnzfFwChbqWeZc7tM9vvJZVRadYFUDakfzy7W0LpYC0cvvK0xT82qlBsk38lQhJ/Hps5A=="
},
"@ffmpeg/ffmpeg": {
"version": "0.12.10",
"resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.12.10.tgz",
"integrity": "sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==",
"requires": {
"@ffmpeg/types": "^0.12.2"
}
},
"@ffmpeg/types": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@ffmpeg/types/-/types-0.12.2.tgz",
"integrity": "sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA=="
},
"@firebase/analytics": { "@firebase/analytics": {
"version": "0.6.18", "version": "0.6.18",
"resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.6.18.tgz", "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.6.18.tgz",
@@ -64286,6 +64357,15 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
}, },
"mux.js": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.3.0.tgz",
"integrity": "sha512-/QTkbSAP2+w1nxV+qTcumSDN5PA98P0tjrADijIzQHe85oBK3Akhy9AHlH0ne/GombLMz1rLyvVsmrgRxoPDrQ==",
"requires": {
"@babel/runtime": "^7.11.2",
"global": "^4.4.0"
}
},
"nan": { "nan": {
"version": "2.17.0", "version": "2.17.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
+4 -1
View File
@@ -11,6 +11,7 @@ import { environment } from 'src/environments/environment';
import { Storage } from '@ionic/storage'; import { Storage } from '@ionic/storage';
import { ChatController } from './controller/chat'; import { ChatController } from './controller/chat';
import { register } from 'swiper/element/bundle'; import { register } from 'swiper/element/bundle';
import { DomSanitizer } from '@angular/platform-browser';
const CUSTOM_DATE_FORMATS: NgxMatDateFormats = { const CUSTOM_DATE_FORMATS: NgxMatDateFormats = {
parse: { parse: {
@@ -39,9 +40,11 @@ export class AppComponent {
private statusBar: StatusBar, private statusBar: StatusBar,
public ThemeService: ThemeService, public ThemeService: ThemeService,
private storage: Storage, private storage: Storage,
private ChatSystemService: ChatSystemService private ChatSystemService: ChatSystemService,
private sanitizer: DomSanitizer
) { ) {
window["sanitizer"] = this.sanitizer
this.initializeApp(); this.initializeApp();
this.storage.set('version', environment.version).then(() => {}) this.storage.set('version', environment.version).then(() => {})
ChatController.ChatSystemService = this.ChatSystemService ChatController.ChatSystemService = this.ChatSystemService
+20 -11
View File
@@ -22,6 +22,8 @@ export class TokenInterceptor implements HttpInterceptor {
null null
); );
private excludedDomains = ['Login', environment.apiChatUrl]; // Add the domains you want to exclude
constructor(private http: HttpClient, private router: Router,) { } constructor(private http: HttpClient, private router: Router,) { }
@@ -29,6 +31,11 @@ export class TokenInterceptor implements HttpInterceptor {
request: HttpRequest<any>, request: HttpRequest<any>,
next: HttpHandler next: HttpHandler
): Observable<HttpEvent<any>> { ): Observable<HttpEvent<any>> {
if (this.shouldExcludeDomain(request)) {
return next.handle(request);
}
if (SessionStore.user.Authorization) { if (SessionStore.user.Authorization) {
request = this.addToken(request, SessionStore.user.Authorization); request = this.addToken(request, SessionStore.user.Authorization);
} }
@@ -44,23 +51,24 @@ export class TokenInterceptor implements HttpInterceptor {
); );
} }
private shouldExcludeDomain(request: HttpRequest<any>): boolean {
const url = request.url.toLowerCase();
return this.excludedDomains.some((domain) => url.includes(domain.toLowerCase()));
}
private addToken(request: HttpRequest<any>, token: string) { private addToken(request: HttpRequest<any>, token: string) {
if(request.url.includes("Login")) { return request.clone({
return request.clone({}); setHeaders: {
} else { //'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
return request.clone({ },
setHeaders: { });
//'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
},
});
}
} }
private handle401Error(request: HttpRequest<any>, next: HttpHandler) { private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
// if not getting the new token yet
if (!this.isRefreshing) { if (!this.isRefreshing) {
this.isRefreshing = true; this.isRefreshing = true;
this.refreshTokenSubject.next(null); this.refreshTokenSubject.next(null);
@@ -73,6 +81,7 @@ export class TokenInterceptor implements HttpInterceptor {
}) })
); );
} else { } else {
// get new token
return this.refreshTokenSubject.pipe( return this.refreshTokenSubject.pipe(
filter((token) => token != null), filter((token) => token != null),
take(1), take(1),
@@ -5,7 +5,7 @@
<fa-icon icon="chevron-left" class="menu-icon font-awesome-1"></fa-icon> <fa-icon icon="chevron-left" class="menu-icon font-awesome-1"></fa-icon>
</div> </div>
<div class="middle add-ellipsis"> <div class="middle ">
{{file.title}} {{file.title}}
</div> </div>
@@ -40,19 +40,23 @@
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" [(ngModel)]="capturedImage" <ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" [(ngModel)]="capturedImage"
name="image" ngDefaultControl [src]="'data:image/jpg;base64,' + seleted.FileBase64" name="image" ngDefaultControl [src]="'data:image/jpg;base64,' + seleted.Base64"
(click)="imageSize(capturedImage)" style="height: 69px;"></ion-img> (click)="imageSize(capturedImage)" style="height: 69px;"></ion-img>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video'" width="70" height="70" <video class="55" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && publicationTitle == ActionType.edit" width="70" height="70"
controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline"> controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.FileBase64"> <source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.Base64">
</video> </video>
<video class="src" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && publicationTitle != ActionType.edit" width="70" height="70"
controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.url">
</video>
</div> </div>
<!-- Display the blurred image and count if there are more images --> <!-- Display the blurred image and count if there are more images -->
<ion-thumbnail *ngIf="seletedContent.length > displayLimit" lot="start"> <ion-thumbnail *ngIf="seletedContent.length > displayLimit" lot="start">
<ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].base64" <ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].Base64"
style="filter: blur(5px);"></ion-img> style="filter: blur(5px);"></ion-img>
<p>mais {{ seletedContent.length - displayLimit }}</p> <p>mais {{ seletedContent.length - displayLimit }}</p>
@@ -22,7 +22,6 @@ import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
import { PublicationFolderService } from 'src/app/store/publication-folder.service'; import { PublicationFolderService } from 'src/app/store/publication-folder.service';
import { RouteService } from 'src/app/services/route.service'; import { RouteService } from 'src/app/services/route.service';
import { FileService } from 'src/app/services/functions/file.service'; import { FileService } from 'src/app/services/functions/file.service';
import { readAndCompressImage } from 'browser-image-resizer';
import { FilePicker } from '@capawesome/capacitor-file-picker'; import { FilePicker } from '@capawesome/capacitor-file-picker';
import { CapacitorVideoPlayer } from 'capacitor-video-player'; import { CapacitorVideoPlayer } from 'capacitor-video-player';
import { CaptureError, CaptureImageOptions, MediaCapture, MediaFile } from '@awesome-cordova-plugins/media-capture/ngx'; import { CaptureError, CaptureImageOptions, MediaCapture, MediaFile } from '@awesome-cordova-plugins/media-capture/ngx';
@@ -31,9 +30,7 @@ import { File } from '@ionic-native/file/ngx';
import { Media } from '@ionic-native/media/ngx'; import { Media } from '@ionic-native/media/ngx';
import { checkFileTypeService } from 'src/app/services/checkFileType.service'; import { checkFileTypeService } from 'src/app/services/checkFileType.service';
import { FileValidatorService } from "src/app/services/file/file-validator.service" import { FileValidatorService } from "src/app/services/file/file-validator.service"
import { App } from '@capacitor/app'; import { PublicationAttachmentEntity } from 'src/app/shared/publication/upload/upload-streaming.service';
import { Router } from '@angular/router';
const config = { const config = {
quality: 0.5, quality: 0.5,
maxWidth: 800, maxWidth: 800,
@@ -95,6 +92,13 @@ export class NewPublicationPage implements OnInit {
publicationTitle: string; publicationTitle: string;
imgUrl: any; imgUrl: any;
ActionType = {
newRapid : "1",
new: "2",
edit: "3"
}
Defaultimage: any = ''; Defaultimage: any = '';
photo: SafeResourceUrl; photo: SafeResourceUrl;
@@ -115,7 +119,7 @@ export class NewPublicationPage implements OnInit {
photoOrVideo: boolean = false; photoOrVideo: boolean = false;
fileType = ""; fileType = "";
filecontent: boolean; filecontent: boolean;
seletedContent: any[] = [] seletedContent: PublicationAttachmentEntity[] = []
// Set a limit for the number of images to display // Set a limit for the number of images to display
displayLimit = 4; displayLimit = 4;
filesSizeSum = 0; filesSizeSum = 0;
@@ -136,8 +140,7 @@ export class NewPublicationPage implements OnInit {
public FileService: FileService, public FileService: FileService,
private mediaCapture: MediaCapture, private mediaCapture: MediaCapture,
public checkFileType: checkFileTypeService, public checkFileType: checkFileTypeService,
private FileValidatorService: FileValidatorService, private FileValidatorService: FileValidatorService
private router: Router,
) { ) {
this.publicationType = this.navParams.get('publicationType'); this.publicationType = this.navParams.get('publicationType');
@@ -146,6 +149,18 @@ export class NewPublicationPage implements OnInit {
if (this.publication) { if (this.publication) {
this.seletedContent = this.publication.Files; this.seletedContent = this.publication.Files;
this.filecontent = true; this.filecontent = true;
this.seletedContent = this.publication.Files.map(e => {
return new PublicationAttachmentEntity(
{
base64: e.FileBase64,
extension: e.FileExtension,
OriginalFileName: e.OriginalFileName,
FileType: this.checkFileType.checkFileType(e.FileExtension) as any
}
)
})
} }
console.log('Edit', this.publication) console.log('Edit', this.publication)
this.publicationTitle = 'Nova Publicação'; this.publicationTitle = 'Nova Publicação';
@@ -165,12 +180,16 @@ export class NewPublicationPage implements OnInit {
recursive: true recursive: true
}); });
document.addEventListener("click", clickOutside, false); try {
function clickOutside(e) { document.addEventListener("click", clickOutside, false);
const inside = document.getElementById('container-multiselect').contains(e.target); function clickOutside(e) {
this.photoOrVideo = false; const inside = document.getElementById('container-multiselect').contains(e.target);
console.log(this.photoOrVideo) this.photoOrVideo = false;
} console.log(this.photoOrVideo)
}
} catch (error) {}
} }
// in use // in use
@@ -197,11 +216,14 @@ export class NewPublicationPage implements OnInit {
console.log('take picture', this.removeTextBeforeSlash(picture, ','),) console.log('take picture', this.removeTextBeforeSlash(picture, ','),)
this.filecontent = true; this.filecontent = true;
this.photoOrVideo = false; this.photoOrVideo = false;
let fileObject = {
FileBase64: this.removeTextBeforeSlash(picture, ','), const fileObject = new PublicationAttachmentEntity({
FileExtension: capturedImage.format, base64: this.removeTextBeforeSlash(picture, ','),
extension: capturedImage.format,
FileType: 'image',
OriginalFileName: 'image' OriginalFileName: 'image'
} })
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
@@ -255,11 +277,14 @@ export class NewPublicationPage implements OnInit {
.then(async (content) => { .then(async (content) => {
this.filecontent = true; this.filecontent = true;
let fileObject = { let fileObject = new PublicationAttachmentEntity({
FileBase64: 'data:video/mp4;base64,' + content.data, base64: 'data:video/mp4;base64,'+content.data,
FileExtension: 'mp4', extension: 'mp4',
OriginalFileName: 'video' OriginalFileName: 'record',
} FileType: 'video'
})
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
}) })
.catch((err) => console.error(err)); .catch((err) => console.error(err));
@@ -282,7 +307,7 @@ export class NewPublicationPage implements OnInit {
({ ({
multiple: true, multiple: true,
}); });
console.log(result.files) console.log(result.files)
result.files.forEach(element => { result.files.forEach(element => {
this.filesSizeSum = this.filesSizeSum + element.size this.filesSizeSum = this.filesSizeSum + element.size
@@ -297,18 +322,29 @@ export class NewPublicationPage implements OnInit {
console.log(content) console.log(content)
this.filecontent = true; this.filecontent = true;
let fileObject; let fileObject;
if (this.removeTextBeforeSlash(element.mimeType, '/') == "mp4") { if(this.removeTextBeforeSlash(element.mimeType, '/') == "mp4") {
fileObject = {
FileBase64: 'data:video/mp4;base64,' + content.data, const extension = this.removeTextBeforeSlash(element.mimeType, '/')
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'video' fileObject = new PublicationAttachmentEntity({
} base64: content.data,
extension: extension,
OriginalFileName: 'video',
FileType: 'video'
})
} else { } else {
fileObject = {
FileBase64: content.data, const extension = this.removeTextBeforeSlash(element.mimeType, '/')
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'image' fileObject = new PublicationAttachmentEntity({
} base64: content.data,
extension: extension,
OriginalFileName: 'image',
FileType: 'image'
})
} }
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
@@ -409,52 +445,51 @@ export class NewPublicationPage implements OnInit {
if (this.Form.invalid) return false if (this.Form.invalid) return false
if (this.seletedContent.length != 0) {
if (this.publicationType == '3') { if (this.publicationType == '3') {
const loader = this.toastService.loading() const loader = this.toastService.loading()
// has file // has file
if (this.PublicationFolderService.PublicationHasImage(this.publication)) { if (this.PublicationFolderService.PublicationHasImage(this.publication)) {
this.publication = { this.publication = {
DateIndex: this.publication.DateIndex, DateIndex: this.publication.DateIndex,
DocumentId: this.publication.DocumentId, DocumentId: this.publication.DocumentId,
ProcessId: this.publication.ProcessId, ProcessId: this.publication.ProcessId,
Title: this.pub.Title, Title: this.pub.Title,
Message: this.pub.Message, Message: this.pub.Message,
DatePublication: this.publication.DatePublication, DatePublication: this.publication.DatePublication,
OriginalFileName: this.publication.OriginalFileName, OriginalFileName: this.publication.OriginalFileName,
Files: this.seletedContent, Files: this.seletedContent,
} }
/* } else if (this.capturedVideo != '' && this.capturedImage == '') { /* } else if (this.capturedVideo != '' && this.capturedImage == '') {
this.publication = { this.publication = {
DateIndex: this.publication.DateIndex, DateIndex: this.publication.DateIndex,
DocumentId: this.publication.DocumentId, DocumentId: this.publication.DocumentId,
ProcessId: this.publication.ProcessId, ProcessId: this.publication.ProcessId,
Title: this.pub.Title, Title: this.pub.Title,
Message: this.pub.Message, Message: this.pub.Message,
DatePublication: this.publication.DatePublication, DatePublication: this.publication.DatePublication,
OriginalFileName: this.publication.OriginalFileName || 'video', OriginalFileName: this.publication.OriginalFileName || 'video',
Files: this.seletedContent, Files: this.seletedContent,
FileExtension: 'mp4', FileExtension: 'mp4',
} }
} */ } */
// no names // no names
} else if (!this.PublicationFolderService.PublicationHasImage(this.publication)) { } else if (!this.PublicationFolderService.PublicationHasImage(this.publication)) {
this.publication = { this.publication = {
DateIndex: this.publication.DateIndex, DateIndex: this.publication.DateIndex,
DocumentId: this.publication.DocumentId, DocumentId: this.publication.DocumentId,
ProcessId: this.publication.ProcessId, ProcessId: this.publication.ProcessId,
Title: this.pub.Title, Title: this.pub.Title,
Message: this.pub.Message, Message: this.pub.Message,
DatePublication: this.publication.DatePublication, DatePublication: this.publication.DatePublication,
OriginalFileName: this.publication.OriginalFileName, OriginalFileName: this.publication.OriginalFileName,
Files: this.seletedContent, Files: this.seletedContent,
} }
} /* else { } /* else {
this.publication = { this.publication = {
DateIndex: this.publication.DateIndex, DateIndex: this.publication.DateIndex,
DocumentId: this.publication.DocumentId, DocumentId: this.publication.DocumentId,
@@ -470,96 +505,90 @@ export class NewPublicationPage implements OnInit {
} */ } */
try { try {
const response = await this.publications.UpdatePublication(this.publication.ProcessId, this.publication).toPromise() const response = await this.publications.UpdatePublication(this.publication.ProcessId, this.publication).toPromise()
this.httpErrorHandle.httpsSucessMessagge('Editar publicação') this.httpErrorHandle.httpsSucessMessagge('Editar publicação')
console.log({ response }) console.log({ response })
this.close();
} catch (error) {
if (error.status == 404) {
this.PublicationFolderService.deletePost(this.publication.ProcessId, this.publication.DocumentId)
this.close(); this.close();
} catch (error) {
if (error.status == 404) {
this.PublicationFolderService.deletePost(this.publication.ProcessId, this.publication.DocumentId)
this.close();
}
this.httpErrorHandle.httpStatusHandle(error)
} finally {
loader.remove()
} }
this.httpErrorHandle.httpStatusHandle(error)
} } finally {
else { loader.remove()
const date = formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss')
/* this.seletedContent = this.seletedContent.map((e) => {
if(e.FileExtension == "mp4") {
return {
FileBase64: e.FileBase64,
FileExtension: 'data:video/mp4;base64,'+e.FileExtension,
OriginalFileName: "video",
}
}
return e
}) */
/* if (this.capturedImage != '') { */
this.publication = {
DateIndex: date,
DocumentId: null,
ProcessId: this.folderId,
Title: this.pub.Title,
Message: this.pub.Message,
DatePublication: date,
OriginalFileName: this.capturedImageTitle || 'foto',
Files: this.seletedContent,
/* FileExtension: 'jpeg', */
}
/* } else if (this.capturedVideo != '') {
this.publication = {
DateIndex: date,
DocumentId: null,
ProcessId: this.folderId,
Title: this.pub.Title,
Message: this.pub.Message,
DatePublication: date,
OriginalFileName: this.capturedImageTitle || 'video',
Files: this.seletedContent,
FileExtension: 'mp4',
}
} */
const loader = this.toastService.loading()
try {
await this.publications.CreatePublication(this.folderId, this.publication).toPromise();
this.httpErrorHandle.httpsSucessMessagge('Criar publicação')
if(window["sharedContent"]) {
this.router.navigate(['/home/publications', this.folderId]);
return
}
this.close();
} catch (error) {
this.httpErrorHandle.httpStatusHandle(error)
} finally {
loader.remove()
}
} }
this.PublicationFolderService.getPublicationsIds(this.folderId)
} else {
this.httpErrorHandle.validationMessagge("noFileSelected")
} }
else {
const date = formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss')
/* this.seletedContent = this.seletedContent.map((e) => {
if(e.FileExtension == "mp4") {
return {
FileBase64: e.FileBase64,
FileExtension: 'data:video/mp4;base64,'+e.FileExtension,
OriginalFileName: "video",
}
}
return e
}) */
/* if (this.capturedImage != '') { */
this.publication = {
DateIndex: date,
DocumentId: null,
ProcessId: this.folderId,
Title: this.pub.Title,
Message: this.pub.Message,
DatePublication: date,
OriginalFileName: this.capturedImageTitle || 'foto',
Files: this.seletedContent,
/* FileExtension: 'jpeg', */
}
/* } else if (this.capturedVideo != '') {
this.publication = {
DateIndex: date,
DocumentId: null,
ProcessId: this.folderId,
Title: this.pub.Title,
Message: this.pub.Message,
DatePublication: date,
OriginalFileName: this.capturedImageTitle || 'video',
Files: this.seletedContent,
FileExtension: 'mp4',
}
} */
const loader = this.toastService.loading()
try {
await this.publications.CreatePublication(this.folderId, this.publication).toPromise();
this.close();
this.httpErrorHandle.httpsSucessMessagge('Criar publicação')
window["sharedContent"] = null;
window["endSharedContent"] = null;
this.close();
} catch (error) {
this.httpErrorHandle.httpStatusHandle(error)
} finally {
loader.remove()
}
}
this.PublicationFolderService.getPublicationsIds(this.folderId)
} }
@@ -567,10 +596,6 @@ export class NewPublicationPage implements OnInit {
this.modalController.dismiss(this.publication).then(() => { this.modalController.dismiss(this.publication).then(() => {
this.showLoader = true; this.showLoader = true;
}); });
if(window["sharedContent"]) {
this.closeApp();
}
} }
clear() { clear() {
@@ -753,23 +778,15 @@ export class NewPublicationPage implements OnInit {
if (this.checkFileType.checkFileType(FileExtension) == 'image' || this.checkFileType.checkFileType(FileExtension) == 'video') { if (this.checkFileType.checkFileType(FileExtension) == 'image' || this.checkFileType.checkFileType(FileExtension) == 'video') {
let resultUrl = decodeURIComponent(element.url); let resultUrl = decodeURIComponent(element.url);
Filesystem.readFile({ path: resultUrl }).then(async (content) => { Filesystem.readFile({ path: resultUrl }).then(async (content) => {
let fileObject;
if (this.checkFileType.checkFileType(FileExtension) == 'image') {
fileObject = {
FileBase64: this.removeTextBeforeSlash(content.data, ','),
FileExtension: FileExtension,
OriginalFileName: 'shared',
}
} else if (this.checkFileType.checkFileType(FileExtension) == 'video') { let fileObject = new PublicationAttachmentEntity(
fileObject = { {
FileBase64: 'data:video/mp4;base64,' + this.removeTextBeforeSlash(content.data, ','), base64: this.removeTextBeforeSlash(content.data, ','),
FileExtension: FileExtension, extension: FileExtension,
OriginalFileName: 'shared', OriginalFileName: "share-content",
FileType: this.checkFileType.checkFileType(FileExtension) as any
} }
)
}
console.log('shared base', content.data)
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
}) })
@@ -791,9 +808,5 @@ export class NewPublicationPage implements OnInit {
this.seletedContent.splice(index, 1) this.seletedContent.splice(index, 1)
} }
closeApp() {
App.exitApp()
}
} }
@@ -19,12 +19,9 @@
<div class="title-content width-100 d-flex justify-space-between"> <div class="title-content width-100 d-flex justify-space-between">
<div class="div-title flex-grow-1"> <div class="div-title flex-grow-1">
<ion-label class="title font-25-em">Acções</ion-label> <ion-label class="title font-25-em">Acções</ion-label>
<!-- <div>
<input type="file" (change)="onFileSelect($event)" />
</div> -->
</div> </div>
<div class="div-icon"> <div *ngIf="!intent" class="div-icon">
<button *ngIf="p.userPermission([p.permissionList.Actions.create])" title="Adicionar nova ação presidencial" class="btn-no-color" (click)="AddPublicationFolder()"> <button *ngIf="p.userPermission([p.permissionList.Actions.create])" title="Adicionar nova ação presidencial" class="btn-no-color" (click)="AddPublicationFolder()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="icon-only" src='assets/images/icons-add.svg'></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="icon-only" src='assets/images/icons-add.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="icon-only" src='assets/images/theme/gov/icons-add.svg'></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="icon-only" src='assets/images/theme/gov/icons-add.svg'></ion-icon>
@@ -34,12 +31,12 @@
<ion-icon class=" font-45-em" src="assets/images/theme/gov/icon-reload.svg"></ion-icon> <ion-icon class=" font-45-em" src="assets/images/theme/gov/icon-reload.svg"></ion-icon>
</button> </button>
</div> </div>
<!-- <div *ngIf="intent" class="div-icon"> <div *ngIf="intent" class="div-icon">
<button title="Atualizar" class="btn-no-color" (click)="close()"> <button title="Atualizar" class="btn-no-color" (click)="close()">
<ion-icon class=" font-45-em" src="assets/images/icons-search-close.svg"></ion-icon> <ion-icon class=" font-45-em" src="assets/images/icons-search-close.svg"></ion-icon>
</button> </button>
</div> --> </div>
</div> </div>
</div> </div>
+2 -1
View File
@@ -8,10 +8,11 @@ import { ExpedienteTaskPipe } from './expediente-task.pipe';
import { ParticipantsPipe } from './participants.pipe'; import { ParticipantsPipe } from './participants.pipe';
import { SafehtmlPipe } from './safehtml.pipe'; import { SafehtmlPipe } from './safehtml.pipe';
import { EventoApprovePipe } from './evento-approve.pipe'; import { EventoApprovePipe } from './evento-approve.pipe';
import { SafePipe } from './safe.pipe';
@NgModule({ @NgModule({
declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe, SafehtmlPipe, EventoApprovePipe], declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe, SafehtmlPipe, EventoApprovePipe, SafePipe],
exports: [FilterPipe, SafehtmlPipe], exports: [FilterPipe, SafehtmlPipe],
imports: [] imports: []
}) })
+8
View File
@@ -0,0 +1,8 @@
import { SafePipe } from './safe.pipe';
describe('SafePipe', () => {
it('create an instance', () => {
const pipe = new SafePipe();
expect(pipe).toBeTruthy();
});
});
+13
View File
@@ -0,0 +1,13 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
@Pipe({
name: 'safe'
})
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(url: string): SafeUrl {
return this.sanitizer.bypassSecurityTrustUrl(url);
}
}
+425 -21
View File
@@ -1,46 +1,450 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import * as signalR from "@microsoft/signalr" import * as signalR from "@microsoft/signalr"
import { SessionStore } from '../store/session.service'; import { SessionStore } from '../store/session.service';
import { v4 as uuidv4 } from 'uuid'
import { HttpClient, HttpHeaders, HttpEventType } from '@angular/common/http';
import { CMAPIService } from '../shared/repository/CMAPI/cmapi.service';
import { HubConnectionBuilder } from '@microsoft/signalr';
import { ok, err, Result } from 'neverthrow';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class SocketConnectionMCRService { export class SocketConnectionMCRService {
// private callbacks: Function[] = []
// private onDisconnect: Function[] = []
// private onConnect: Function[] = []
constructor() { } constructor(private http: HttpClient, private _CMAPIService: CMAPIService) {
window["http"] = this.http
}
// connect() {
// var connection = new signalR.HubConnectionBuilder()
// .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
// accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
// }).configureLogging(signalR.LogLevel.Information)
// .build();
// connection.on("ReceiveMessage", (message) => {
// console.log("ReceiveMessage", message)
// })
// connection.onreconnected((connectionId) => {
// console.assert(connection.state === signalR.HubConnectionState.Connected);
// console.log(`Reconnected with connectionId: ${connectionId}`);
// });
// connection.start()
// .then(() => {
// console.log("SignalR connection started.");
// })
// .catch((error) => {
// console.error("Error starting SignalR connection:", error);
// });
// connection.onclose((error) => {
// connection.start()
// console.log("SignalR connection closed:", error);
// });
// }
// subscribe(callback) {
// this.callbacks.push(callback);
// }
// unsubscribe(callback) {
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
// }
// onDisconnectCallback(callback) {
// this.onDisconnect.push(callback)
// }
// onConnectCallback(callback) {
// this.onConnect.push(callback)
// }
}
class ReconnectingWebSocketSignalR {
private connection: any
isOpen: boolean = false
private callbacks: Function[] = []
private onDisconnect: Function[] = []
private onConnect: Function[] = []
private whenConnected: Function[] = []
stop = true
constructor() {}
connect() { connect() {
console.log("try to connect=================================")
this.stop = false
var connection = new signalR.HubConnectionBuilder() this.connection = new signalR.HubConnectionBuilder()
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", { .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => SessionStore.user.Authorization transport: signalR.HttpTransportType.LongPolling,
accessTokenFactory: () => SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information) }).configureLogging(signalR.LogLevel.Information)
.build(); .build();
connection.on("ReceiveMessage", (message) => { this.connection.start()
console.log("ReceiveMessage", message)
})
connection.onreconnected((connectionId) => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log(`Reconnected with connectionId: ${connectionId}`);
});
connection.start()
.then(() => { .then(() => {
console.log("SignalR connection started."); this.isOpen = true;
console.log('WebSocket connection established');
this.onConnect.forEach(callback => callback());
this.whenConnected.forEach(callback => callback())
}) })
.catch((error) => { .catch((error) => {
console.error("Error starting SignalR connection:", error); console.error("Error starting SignalR connection:", error);
}); });
connection.onclose((error) => {
connection.start()
console.log("SignalR connection closed:", error);
});
this.connection.on("ReceiveMessage", (message) => {
const data: any = JSON.parse(message)
console.log("ReceiveMessage", data)
this.callbacks.forEach(callback => callback(data));
})
this.connection.onclose((error) => {
console.log('WebSocket connection closed..');
this.isOpen = false;
this.onDisconnect.forEach(callback => callback());
// Attempt to reconnect after a delay
if(this.stop == false) {
setTimeout(() => {
this.connect();
}, 1000); // Adjust the delay as needed
}
});
}
commit(path): Promise<Result<true, false>> {
return new Promise((resolve, reject) => {
this.connection.invoke("CommitUpload", path).then((e) => {
console.log("commit message", e)
resolve(ok(true))
}).catch(err => {
resolve(err(false))
console.error(err.toString())
});
})
}
disconnect() {
this.stop = true
if(this.isOpen == true) {
this.connection.stop()
.then(() => {
console.log('WebSocket connection was closed by client');
this.isOpen = false;
this.onDisconnect.forEach(callback => callback());
console.log("SignalR connection stopped.");
})
.catch((error) => {
console.error("Error stopping SignalR connection by client:", error);
});
}
}
subscribe(callback) {
this.callbacks.push(callback);
}
unsubscribe(callback) {
this.callbacks = this.callbacks.filter(cb => cb !== callback);
}
onDisconnectCallback(callback) {
this.onDisconnect.push(callback)
}
onConnectCallback(callback) {
this.onConnect.push(callback)
}
registerWhenConnected(f: Function) {
if(this.isOpen) {
f();
} else {
this.whenConnected.push(f);
}
}
}
interface socketResponse {
index: string
Guid: string
IsCompleted: Boolean
}
// class ReconnectingWebSocket {
// private url: string
// private socket
// isOpen: boolean
// private callbacks: Function[] = []
// private onDisconnect: Function[] = []
// private onConnect: Function[] = []
// private whenConnected: Function[] = []
// private stop = true
// http: HttpClient = window["http"]
// constructor(url) {
// this.url = url;
// this.socket = null;
// this.isOpen = false;
// }
// connect() {
// this.socket = new WebSocket(this.url);
// this.socket.addEventListener('open', (event) => {
// this.isOpen = true;
// console.log('WebSocket connection established');
// // Example: Send a message to the server
// this.socket.send('Hello, WebSocket Server!');
// this.onConnect.forEach(callback => callback());
// this.whenConnected.forEach(callback => callback())
// });
// this.socket.addEventListener('message', (event) => {
// const data: socketResponse = JSON.parse(event.data)
// this.callbacks.forEach(callback => callback(data));
// });
// this.socket.addEventListener('close', (event) => {
// console.log('WebSocket connection closed');
// this.isOpen = false;
// this.onDisconnect.forEach(callback => callback());
// // Attempt to reconnect after a delay
// if(this.stop == false) {
// setTimeout(() => {
// this.connect();
// }, 1000); // Adjust the delay as needed
// }
// });
// }
// send(message) {
// if (this.isOpen) {
// this.socket.send(message);
// } else {
// console.error('WebSocket connection is not open. Unable to send message.');
// }
// }
// disconnect() {
// this.stop = true
// if (this.isOpen) {
// this.isOpen = false;
// this.socket.close();
// }
// }
// subscribe(callback) {
// this.callbacks.push(callback);
// }
// unsubscribe(callback) {
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
// }
// onDisconnectCallback(callback) {
// this.onDisconnect.push(callback)
// }
// onConnectCallback(callback) {
// this.onConnect.push(callback)
// }
// registerWhenConnected(f: Function) {
// if(this.isOpen) {
// f();
// } else {
// this.whenConnected.push(f);
// }
// }
// }
// export class ObjectMergeNotification{
// socket = new ReconnectingWebSocket('ws://localhost:3002');
// callbacks: {[GUID: string]: Function} = {}
// runWatch = true
// CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
// watchCount = 0
// constructor() {
// this.socket.onDisconnectCallback(()=> {
// console.log("run watch")
// this.runWatch = true
// this.watch()
// })
// this.socket.onConnectCallback(()=> {
// console.log("open trigger")
// this.runWatch = false
// })
// this.socket.subscribe((data: socketResponse) => {
// if(data.IsCompleted == true) {
// console.log("==================!!!====================")
// try {
// this.callbacks[data.Guid](data)
// delete this.callbacks[data.Guid]
// } catch (error) {}
// } else {
// console.log("else", data)
// }
// })
// this.watch()
// }
// connect() {
// this.socket.connect()
// }
// async watch() {
// this.watchCount = 0;
// if(this.runWatch) {
// setTimeout(async () => {
// for(const [key, funx] of Object.entries(this.callbacks)) {
// const request = await this.CMAPIService.getVideoHeader(key)
// if(request.isOk()) {
// funx()
// delete this.callbacks[key]
// }
// }
// this.watchCount++
// if(this.watchCount <= 15) {
// this.watch()
// } else {
// this.runWatch = false
// }
// }, 1000)
// } else {
// console.log("end loop============================")
// }
// }
// close() {
// this.socket.disconnect();
// this.watchCount = 0;
// this.runWatch = false
// }
// subscribe(GUID, callback:Function) {
// this.callbacks[GUID] = callback;
// }
// unsubscribe(GUID) {
// delete this.callbacks[GUID]
// }
// }
export class ObjectMergeNotification{
socket = new ReconnectingWebSocketSignalR()
callbacks: {[GUID: string]: Function} = {}
runWatch = true
CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
watchCount = 0
constructor() {
this.socket.onDisconnectCallback(()=> {
console.log("run watch")
this.runWatch = true
this.watch()
})
this.socket.onConnectCallback(()=> {
console.log("open trigger")
this.runWatch = false
})
this.socket.subscribe((data: socketResponse) => {
if(data.IsCompleted == true) {
console.log("==================!!!====================")
try {
this.callbacks[data.Guid](data)
delete this.callbacks[data.Guid]
} catch (error) {}
} else {
console.log("else", data)
}
})
this.socket.connect();
this.watch()
}
connect() {
this.socket.connect();
}
close() {
this.socket.disconnect();
this.watchCount = 0;
this.runWatch = false
}
async watch() {
// this.watchCount = 0;
// if(this.runWatch) {
// setTimeout(async () => {
// for(const [key, funx] of Object.entries(this.callbacks)) {
// const request = await this.CMAPIService.getVideoHeader(key)
// if(request.isOk()) {
// funx()
// delete this.callbacks[key]
// }
// }
// this.watchCount++
// if(this.watchCount <= 15) {
// this.watch()
// } else {
// this.runWatch = false
// }
// }, 1000)
// } else {
// console.log("end loop============================")
// }
}
subscribe(GUID, callback:Function) {
this.callbacks[GUID] = callback;
}
unsubscribe(GUID) {
delete this.callbacks[GUID]
} }
} }
-91
View File
@@ -12,97 +12,6 @@ export class StreamService {
window["StreamService"] = this window["StreamService"] = this
} }
async uploadFile() {
const API_URL = 'http://localhost:3000/upload'; // Replace with your server URL
const filePath = 'path/to/large-file.zip'; // Replace with the path to your file
const fileName = 'my-file'; // Specify your desired filename
const fileExtension = 'zip'; // Specify the file extension
const headers = new HttpHeaders()
.append('X-File-Name', fileName)
.append('X-File-Extension', fileExtension);
const file = await this.readFileInChunks(filePath);
const chunkSize = 1024 * 1024; // 1 MB chunk size (adjust as needed)
for (let offset = 0; offset < file.length; offset += chunkSize) {
const chunk = file.slice(offset, offset + chunkSize);
// await this.uploadChunk(API_URL, chunk, headers);
}
console.log('Upload completed.');
}
async readFileInChunks(filePath: string): Promise<Uint8Array> {
const response = await fetch(filePath);
const reader = response.body.getReader();
const chunks: Uint8Array[] = [];
let done = false;
while (!done) {
const { value, done: isDone } = await reader.read();
if (!isDone) {
chunks.push(value);
}
done = isDone;
}
return new Uint8Array([].concat(...chunks.map((chunk) => Array.from(chunk))));
}
async uploadChunk(url: string, chunks: Uint8Array[], fileName, fileExtension): Promise<void> {
let i = 1
console.log('123', chunks.length)
for(const chunk of chunks) {
try {
console.log("iterate")
const headers = new HttpHeaders()
.append('X-File-Name', fileName)
.append('X-File-Extension', fileExtension)
.append('X-File-Content-Length', chunks.length.toString())
.append('X-File-Index', i.toString())
await this.http.post('http://localhost:3001/upload', chunk.buffer, { headers, responseType: 'blob' }).toPromise();
i++
} catch (error) {
console.error('Upload error:', error);
}
}
}
async uploadChunkNoLoop(url: string, chunk: Uint8Array, fileName, fileExtension, i, length): Promise<void> {
console.log("iterate")
const headers = new HttpHeaders()
.append('X-File-Name', fileName)
.append('X-File-Extension', fileExtension)
.append('X-File-Content-Length', length)
.append('X-File-Index', i.toString())
await this.http.post('http://localhost:3001/upload', chunk.buffer, { headers, responseType: 'blob' }).toPromise();
}
uploadChunk1(chunk: Blob, chunkNumber: number, totalChunks: number, filename: string) {
console.log(chunk)
const headers = new HttpHeaders()
.append('X-File-Name', filename)
.append('X-File-Content-Length', totalChunks.toString())
.append('X-File-Index', chunkNumber.toString())
return this.http.post('http://localhost:3001/upload-chunk', Blob, { headers, responseType: 'blob' });
}
} }
// const text = 'Hello, World00120301010asdf1002sdf 0fsdfasf0001230 12300!\n'; // const text = 'Hello, World00120301010asdf1002sdf 0fsdfasf0001230 12300!\n';
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { CMAPIAPIService } from './cmapi-api.service';
describe('CMAPIAPIService', () => {
let service: CMAPIAPIService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CMAPIAPIService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { HttpServiceService } from 'src/app/services/http/http-service.service';
import { HttpClient, HttpEvent, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root'
})
export class CMAPIAPIService {
constructor( private HttpServiceService: HttpServiceService,
private http: HttpClient,) { }
getVideoHeader(url: string) {
//return this.http.head('http://localhost:3001/static/'+url, { observe: 'response' })
return this.http.head(environment.apiURL+'ObjectServer/StreamFiles?path='+url, { observe: 'response' })
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { CMAPIService } from './cmapi.service';
describe('CMAPIService', () => {
let service: CMAPIService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CMAPIService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
+21
View File
@@ -0,0 +1,21 @@
import { Injectable } from '@angular/core';
import { HttpServiceService } from 'src/app/services/http/http-service.service';
import { HttpClient, HttpEvent, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class CMAPIService {
constructor( private HttpServiceService: HttpServiceService,
private http: HttpClient,) {
window["CMAPIService"] = this
}
getVideoHeader(url: string): Observable<Boolean> {
return this.http.head(url, { observe: 'response' })
.map(response => response.status === 200)
.catch(() => Observable.of(false));
}
}
@@ -23,7 +23,7 @@ export class MiddlewareServiceService {
window["MiddlewareServiceService"] = this window["MiddlewareServiceService"] = this
} }
refreshToken(refreshToken: string){ refreshToken(refreshToken: string) {
const data = { const data = {
refreshToken: refreshToken refreshToken: refreshToken
} }
@@ -158,7 +158,7 @@ export class MiddlewareServiceService {
// =========================================================================== // ===========================================================================
CMAPIFileContent({length, path, index, blobFile}) { CMAPIPing() {
const headers = new HttpHeaders(); const headers = new HttpHeaders();
headers.set('Authorization', 'Bearer ' + SessionStore.user.Authorization); headers.set('Authorization', 'Bearer ' + SessionStore.user.Authorization);
@@ -172,19 +172,16 @@ export class MiddlewareServiceService {
const formData = new FormData(); const formData = new FormData();
formData.append("blobFile", blobFile); formData.append("blobFile", "blobFile");
formData.append("length", length); formData.append("length", "length");
formData.append("index", index.toString()); formData.append("index", "index.toString(");
if(path) {
formData.append("path", path);
}
return this.http.post<IuploadFileLK>(`${geturl}`, formData, options) return this.http.post<IuploadFileLK>(`${geturl}`, formData, options)
} }
GetViewer(DocId: string, FsId: string) { GetViewer(DocId: string, FsId: string) {
const geturl = environment.apiURL + 'ecm/document/viewfile'; const geturl = environment.apiURL + 'ecm/document/viewfile';
let params = new HttpParams(); let params = new HttpParams();
@@ -197,4 +194,39 @@ export class MiddlewareServiceService {
}; };
return this.http.get<string>(`${geturl}`, options); return this.http.get<string>(`${geturl}`, options);
} }
CMAPIFileContent({length, path, index, base64}) {
// const geturl = 'http://localhost:3001/FileHub';
const geturl = environment.apiPCURL + 'FileContent/UploadFile';
const data = {
index,
length,
base64,
path,
}
return this.http.post<IuploadFileLK>(`${geturl}`, data)
}
CMAPIRequestUpload() {
const geturl = environment.apiPCURL + 'FileContent/RequestUpload';
return this.http.get<string>(`${geturl}`)
}
CMAPIUploadStatus() {
const geturl = environment.apiPCURL + 'FileContent/UploadStatus';
return this.http.get<string>(`${geturl}`)
}
tryToReachTheServer() {
let opts = {
headers: {},
}
return this.http.post(environment.apiURL + "UserAuthentication/Login", '', opts)
}
} }
@@ -53,45 +53,32 @@
X X
</div> </div>
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" <div *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && seleted.chucksManager">
name="image" ngDefaultControl [src]="seleted.FileBase64" style="height: 69px;"></ion-img>
<mat-progress-bar
<!-- <div class="progress-container" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video'">
<div class="progress-bar" id="myProgressBar"></div>
</div> -->
<!-- <div *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video'">
<mat-progress-bar
*ngIf="seleted.chucksManager"
mode="determinate" mode="determinate"
style="width: 50%" [style.width]="seleted.chucksManager.uploadPercentage"
></mat-progress-bar> ></mat-progress-bar>
</div> -->
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkDesktop() == true" width="70" height="70" </div>
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'"
name="image" ngDefaultControl [src]="seleted.url" style="height: 69px;"></ion-img>
<video class="sdf" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkDesktop() == true" width="70" height="70"
preload="metadata" webkit-playsinline="webkit-playsinline"> preload="metadata" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.FileBase64"> <source type="video/mp4" [src]="seleted.url">
</video> </video>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkTableDivice() == true" width="70" height="70" <video class="sdfsdf" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkTableDivice() == true" width="70" height="70"
preload="metadata" webkit-playsinline="webkit-playsinline"> preload="metadata" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.FileBase64"> <source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.Base64">
</video> </video>
</div> </div>
</div> </div>
<!-- Display the blurred image and count if there are more images -->
<div *ngIf="seletedContent.length > displayLimit" lot="start">
<ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].FileBase64"
style="filter: blur(5px);"></ion-img>
<p>mais {{ seletedContent.length - displayLimit }}</p>
</div>
<ion-label class="pl-10"> <ion-label class="pl-10">
<p>{{capturedImageTitle}}</p> <p>{{capturedImageTitle}}</p>
@@ -153,6 +140,10 @@
</div> </div>
</ion-label> </ion-label>
</div> </div>
<video id="yourVideoElementId" >videoss</video>
</div> </div>
</ion-content> </ion-content>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { PublicationFormMVService } from './publication-form-mv.service';
describe('PublicationFormMVService', () => {
let service: PublicationFormMVService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(PublicationFormMVService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,9 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class PublicationFormMVService {
constructor() { }
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { UploadStreamingService } from './upload-streaming.service';
describe('UploadStreamingService', () => {
let service: UploadStreamingService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UploadStreamingService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,512 @@
import { Injectable } from '@angular/core';
import { ok, err, Result } from 'neverthrow';
import { ObjectMergeNotification } from 'src/app/services/socket-connection-mcr.service';
import { CMAPIService } from "src/app/shared/repository/CMAPI/cmapi.service"
import { DomSanitizer } from '@angular/platform-browser';
export enum UploadError {
noConnection = 'noConnection',
slow = 'slow'
}
export type IOUploadError = "noConnection" | "slow"
@Injectable({
providedIn: 'root'
})
export class UploadStreamingService {
constructor(
private CMAPIService: CMAPIService,
private sanitizer: DomSanitizer
) {
window["sanitizer"] = this.sanitizer
}
}
class UploadFileUseCase {
CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
constructor() {}
async execute(PublicationAttachmentEntity: PublicationAttachmentEntity): Promise<Result<true, IOUploadError >> {
return new Promise(async (resolve, reject) => {
let path: string;
const length = PublicationAttachmentEntity.chucksManager.chunks.totalChunks.toString()
const readAndUploadChunk = async(index: number) => {
const base64 = await PublicationAttachmentEntity.chucksManager.chunks.getChunks(index)
const uploadRequest = this.CMAPIService.FileContent({length, path: PublicationAttachmentEntity.chucksManager.path, index, base64})
uploadRequest.then((uploadRequest) => {
if(uploadRequest.isOk()) {
PublicationAttachmentEntity.chucksManager.setResponse(index, uploadRequest)
}
})
return uploadRequest;
}
if(!PublicationAttachmentEntity.chucksManager.hasPath()) {
const guidRequest = await this.CMAPIService.RequestUpload()
if(guidRequest.isOk()) {
path = guidRequest.value+".mp4"
PublicationAttachmentEntity.chucksManager.setPath(path)
} else {
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
return resolve(err(UploadError.noConnection))
} else {
return resolve(err(UploadError.slow))
}
}
}
const allRequest: Promise<any>[] = []
let connection = true
let errorMessage: UploadError.noConnection | UploadError.slow
for (let index = 1; ( (index <= PublicationAttachmentEntity.chucksManager.chunks.totalChunks) && connection ); index++) {
const needUpload = PublicationAttachmentEntity.chucksManager.needToUploadChunkIndex(index)
if(needUpload) {
// upload every chunk at onces
// const request = readAndUploadChunk(index).then(async(uploadRequest) => {
// if(uploadRequest.isErr()) {
// connection = false
// const pingRequest = await this.CMAPIService.ping()
// if( pingRequest.isErr()) {
// errorMessage = UploadError.noConnection
// } else {
// errorMessage = UploadError.slow
// }
// }
// })
// allRequest.push(request)
// one by one chunk upload
const request = readAndUploadChunk(index)
allRequest.push(request)
const uploadRequest = await request
if(uploadRequest.isErr()) {
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
return resolve(err(UploadError.noConnection))
} else {
return resolve(err(UploadError.slow))
}
}
}
}
await Promise.all(allRequest)
if(!connection) {
return resolve(err(errorMessage))
} else {
return resolve(ok(true))
}
})
}
}
export class PublicationAttachmentEntity {
url: string
FileExtension: string
FileType: 'image' | 'video'
OriginalFileName: string
blobFile?: File
toUpload = false;
chucksManager : ChucksManager
Base64: string
constructor({base64, extension, blobFile, OriginalFileName, FileType}:PublicationAttachmentEntityParams) {
this.Base64 = base64;
this.FileExtension = extension;
this.blobFile = blobFile
this.OriginalFileName = OriginalFileName
this.FileType = FileType
this.fixFileBase64();
}
fixFileBase64() {
const sanitizer : DomSanitizer = window["sanitizer"]
if(this.FileType == 'image' ) {
if(!this.Base64.startsWith('data:')) {
this.url = 'data:image/jpg;base64,' + this.Base64
// this.url = sanitizer.bypassSecurityTrustUrl('data:image/jpg;base64,' + this.Base64) as any
} else {
this.url = this.Base64
}
} else if (this.FileType == 'video' ) {
if(!this.Base64.startsWith('data:') && !this.Base64.startsWith('http')) {
this.url = 'data:video/mp4;base64,' + this.Base64
// this.url = sanitizer.bypassSecurityTrustUrl('data:video/mp4;base64,' + this.Base64) as any
} else {
this.url = this.Base64
}
}
}
needUpload() {
this.toUpload = true
}
setChunkManger (chunks: Chunks) {
this.chucksManager = new ChucksManager({chunks})
}
get hasChunkManger() {
return this.chucksManager?.chunks
}
get hasChunkManager() {
return this.chucksManager != null
}
}
interface IPublicationFormModelEntity {
DateIndex: any
DocumentId: any
ProcessId: any
Title: any
Message: any
DatePublication: any
Files: PublicationAttachmentEntity[]
}
interface PublicationAttachmentEntityParams {
base64: string,
blobFile?: File
extension: string,
OriginalFileName: string,
FileType: 'image' | 'video'
}
export class PublicationFormModel implements IPublicationFormModelEntity {
constructor() {}
DateIndex: any;
DocumentId: any;
ProcessId: any;
Title: any;
Message: any;
DatePublication: any;
OriginalFileName: string;
Files: PublicationAttachmentEntity[];
hasSet = false
setData(data: IPublicationFormModelEntity) {
if(!this.hasSet) {
Object.assign(this, data)
}
this.hasSet = true
}
}
export class PublicationFormMV {
private UploadFileUseCase = new UploadFileUseCase()
private form = new PublicationFormModel()
ObjectMergeNotification = new ObjectMergeNotification()
constructor() {
// this.ObjectMergeNotification.connect();
}
setDataToFrom(data: IPublicationFormModelEntity) {
this.form.setData(data)
}
private getVideoFiles() {
return this.form.Files.filter( x => x.FileType == 'video')
}
private upload(PublicationAttachmentEntity: PublicationAttachmentEntity) {
return new Promise(async (resolve, reject)=> {
if(!PublicationAttachmentEntity.hasChunkManger) {
const fileBlob = PublicationAttachmentEntity.blobFile;
const fileChunks = new Chunks({chunkSize: 40 })
fileChunks.setFile(fileBlob)
PublicationAttachmentEntity.setChunkManger(fileChunks)
} else if(PublicationAttachmentEntity.chucksManager.doneUpload) {
return resolve(true)
}
let attemp = 0;
let result: Result<true, IOUploadError>
if( PublicationAttachmentEntity.chucksManager.isUploading == false) {
do {
attemp++
PublicationAttachmentEntity.chucksManager.clearManualRetry()
PublicationAttachmentEntity.chucksManager.setUploading()
result = await this.UploadFileUseCase.execute(PublicationAttachmentEntity)
PublicationAttachmentEntity.chucksManager.clearUploading()
} while (attemp<3 && result.isErr() && result.error == 'slow')
if(result.isErr()) {
PublicationAttachmentEntity.chucksManager.setManualRetry()
resolve(false)
} else {
const guid = PublicationAttachmentEntity.chucksManager.path
this.ObjectMergeNotification.subscribe(guid, (data) => {
PublicationAttachmentEntity.chucksManager.contentSetReady()
resolve(true)
})
PublicationAttachmentEntity.chucksManager.doneChunkUpload()
this.ObjectMergeNotification.socket.commit(PublicationAttachmentEntity.chucksManager.path)
resolve(true)
}
} else {
}
})
}
uploadVideosFiles(): Promise<Boolean> {
return new Promise((resolve, reject) => {
// this.ObjectMergeNotification.socket.registerWhenConnected(() => {
const videosFiles = this.getVideoFiles()
const videosFilesToUploads = videosFiles.filter( e => e.FileType == "video")
const Promises: Promise<any>[] = []
for(const file of videosFilesToUploads) {
const promise = this.upload(file)
Promises.push(promise)
}
// Use Promise.all to wait for all promises to resolve
Promise.all(Promises)
.then((results) => {
// Check if every promise resolved successfully
const allPromisesResolvedSuccessfully = results.every((result) => result == true);
if (allPromisesResolvedSuccessfully) {
console.log('All promises resolved successfully.');
resolve(true)
} else {
resolve(false)
console.log('Some promises failed to resolve successfully.');
}
})
.catch((error) => {
resolve(false)
console.error('An error occurred while resolving promises:', error);
});
//})
})
}
}
export class Chunks {
chunkSize: number
private file: File
constructor({chunkSize}) {
this.chunkSize = chunkSize * 1024
}
get totalChunks () {
return Math.ceil(this.file.size / this.chunkSize);
}
setFile(file: File) {
this.file = file
}
// Function to read a chunk of the file
readChunk(start: number, end: number): any {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event: any) => resolve(event.target.result.split(',')[1]);
reader.onerror = (error) => reject(error);
reader.readAsDataURL(this.file.slice(start, end));
});
}
async getChunks(i: number): Promise<string> {
i--
if(i < this.totalChunks) {
const start = i * this.chunkSize;
const end = Math.min(start + this.chunkSize, this.file.size);
const chunk = await this.readChunk(start, end);
return chunk
}
}
}
interface IUploadResponse {
result: Result<any, Error>
attemp: number
}
export class ChucksManager {
chunks: Chunks
uploads: {[key: string]: IUploadResponse } = {}
path: string = undefined
uploadPercentage: string = "1%"
merging = false
onSetPath: Function[] = []
onSetLastChunk: Function[] = []
contentReady = false
manualRetry = false
isUploading = false
subscribeToUseCaseResponse: Function[] = []
getUploadPercentage() {
return this.uploadPercentage
}
get uploadsCount() {
return Object.entries(this.uploads).length
}
get uploadWithSuccessCount() {
const uploadWithSuccess = Object.entries(this.uploads).filter(([index, data])=> data.result.isOk())
return uploadWithSuccess.length
}
get doneUpload() {
return this.chunks.totalChunks == this.uploadWithSuccessCount
}
uploadFunc: Function
constructor({chunks}) {
this.chunks = chunks
}
calculatePercentage(): number {
/**
* Calculate the percentage based on the total and current values.
*
* @param total - The total value.
* @param current - The current value.
* @returns The percentage calculated as (current / total) * 100.
*/
const total = this.chunks.totalChunks
const current = this.uploadWithSuccessCount
if (total === 0) {
return 0; // To avoid division by zero error
}
const percentage: number = (current / total) * 100;
return percentage;
}
setManualRetry() {
this.manualRetry = true
}
clearManualRetry() {
this.manualRetry = false
}
setUploading() {
this.isUploading = true
}
clearUploading() {
this.isUploading = false
}
setPercentage() {
const percentage: number = this.calculatePercentage()
console.log({percentage})
this.uploadPercentage = percentage.toString()+"%"
}
setPath(path: string) {
this.path = path
this.onSetPath.forEach(callback => callback());
}
registerOnSetPath(a: Function) {
this.onSetPath.push(a)
}
registerOnLastChunk(a: Function) {
this.onSetLastChunk.push(a)
}
registerToUseCaseResponse(a: Function) {
this.subscribeToUseCaseResponse.push(a)
}
hasPath() {
return this.path != undefined
}
isIndexRegistered(index) {
if(!this.uploads[index]) {
return false
}
return true
}
needToUploadChunkIndex(index) {
return !this.uploads?.[index]?.result?.isOk()
}
setResponse(index, UploadResponse) {
if(!this.isIndexRegistered(index)) {
this.uploads[index] = {
attemp: 1,
result: UploadResponse
}
console.log({UploadResponse})
} else {
this.uploads[index].attemp++;
this.uploads[index].result = UploadResponse
}
this.setPercentage()
}
doneChunkUpload() {
this.merging = true
this.onSetLastChunk.forEach(callback => callback());
}
contentSetReady() {
this.merging = false
this.contentReady = true
}
}
@@ -39,23 +39,25 @@
<p class="item-content-detail">{{publicationFolderService.FolderDetails[folderId].Detail}}</p> <p class="item-content-detail">{{publicationFolderService.FolderDetails[folderId].Detail}}</p>
<ion-card *ngFor="let publication of publicationFolderService.publicationList[folderId] let i = index"> <ion-card *ngFor="let publication of publicationFolderService.publicationList[folderId] let i = index">
<ion-card-content> <ion-card-content>
<swiper-container [modules]="swiperModules" [speed]=400 navigation="true" [pagination]="{clickable: true, dynamicBullets: true }"> <swiper-container [config]="swiperThumbsConfig" [modules]="swiperModules" [speed]=400 navigation="true" [pagination]="{clickable: true, dynamicBullets: true }">
<swiper-slide *ngFor="let files of publication.Files let k = index"> <swiper-slide *ngFor="let files of publication.Files let k = index" class="centered-slide">
<div (click)="viewPublicationDetail(publication.DocumentId, publication.ProcessId)"> <div class="cool">
<img *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'image'" class="post-img cursor-pointer" <div (click)="viewPublicationDetail(publication.DocumentId, publication.ProcessId)">
[lazyLoad]="'data:image/jpg;base64,' + files.FileBase64"> <img *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'image'" class="post-img cursor-pointer"
[lazyLoad]="'data:image/jpg;base64,' + files.FileBase64">
<video [appVisibility]="onVisibilityChange" #myVideo #videoElement *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="metadata" <video [appVisibility]="onVisibilityChange" #myVideo #videoElement *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="metadata"
webkit-playsinline="webkit-playsinline" class="videoPlayer" (click)="preventVideoPlay($event)"> webkit-playsinline="webkit-playsinline" class="videoPlayer" (click)="preventVideoPlay($event)">
<source [src]="files.FileBase64" type="video/mp4" > <source [src]="files.FileBase64" type="video/mp4" >
</video> </video>
</div>
</div> </div>
</swiper-slide> </swiper-slide>
<!-- <div *ngIf="publication?.Files?.length == 0"> <!-- <div *ngIf="publication?.Files?.length == 0">
@@ -292,3 +292,10 @@ swiper-slide video {
align-items: center; align-items: center;
} }
.centered-slide {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
@@ -15,7 +15,7 @@ import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
import { PublicationFolderService } from 'src/app/store/publication-folder.service'; import { PublicationFolderService } from 'src/app/store/publication-folder.service';
import { AskModalPage } from 'src/app/modals/ask-modal/ask-modal.page'; import { AskModalPage } from 'src/app/modals/ask-modal/ask-modal.page';
import { checkFileTypeService } from 'src/app/services/checkFileType.service'; import { checkFileTypeService } from 'src/app/services/checkFileType.service';
import { PublicationVideoManagerService } from "src/app/services/publication/publication-video-manager.service"; import { PublicationVideoManagerService } from "src/app/services/publication/publication-video-manager.service";
import { StopvideoService } from "src/app/services/stopvideo.service"; import { StopvideoService } from "src/app/services/stopvideo.service";
@Component({ @Component({
selector: 'app-view-publications', selector: 'app-view-publications',
@@ -29,6 +29,18 @@ export class ViewPublicationsPage implements OnInit {
error: any; error: any;
oldpublicationIds = [] oldpublicationIds = []
swiperConfig = {
spaceBetween: 10,
navigation: true,
}
swiperThumbsConfig = {
spaceBetween: 10,
slidesPerView: 4,
freeMode: true,
watchSlidesProgress: true,
}
@Input() folderId: any; @Input() folderId: any;
@Output() addNewPublication = new EventEmitter<any>(); @Output() addNewPublication = new EventEmitter<any>();
@Output() editPublication = new EventEmitter<any>(); @Output() editPublication = new EventEmitter<any>();
@@ -80,7 +92,7 @@ export class ViewPublicationsPage implements OnInit {
onVisibilityChange = (e: boolean) => { onVisibilityChange = (e: boolean) => {
console.log("nice to have", e) console.log("nice to have", e)
if (!e) { if(!e) {
/* this.stopVideo() */ /* this.stopVideo() */
} }
} }
@@ -228,13 +240,13 @@ export class ViewPublicationsPage implements OnInit {
this.publicationFolderService.revertPublicationOrder(folderId) this.publicationFolderService.revertPublicationOrder(folderId)
} else { } else {
let a: any = Object.assign({}, this.publicationFolderService.publicationList[folderId][findIndex]) let a: any = Object.assign({},this.publicationFolderService.publicationList[folderId][findIndex])
let b: any = Object.assign({}, publicationDetails) let b: any = Object.assign({}, publicationDetails)
a.Files = a.Files.length a.Files = a.Files.length
b.Files = b.Files.length b.Files = b.Files.length
if (JSON.stringify(a) != JSON.stringify(b)) { if(JSON.stringify(a) != JSON.stringify(b)) {
// console.log({a, b}) // console.log({a, b})
this.publicationFolderService.publicationList[folderId][findIndex] = publicationDetails this.publicationFolderService.publicationList[folderId][findIndex] = publicationDetails
@@ -314,12 +326,11 @@ export class ViewPublicationsPage implements OnInit {
}, },
}); });
modal.onDidDismiss().then(async (res) => { modal.onDidDismiss().then((res) => {
if (res.data == 'Yes') { if (res.data == 'Yes') {
const loader = this.toastService.loading(); const loader = this.toastService.loading();
try { try {
await this.publications.DeletePresidentialAction(folderId).toPromise(); this.publications.DeletePresidentialAction(folderId).toPromise();
window["refreshPublication"]();
this.httpErrorHandle.httpsSucessMessagge('Eliminar Acção') this.httpErrorHandle.httpsSucessMessagge('Eliminar Acção')
} catch (error) { } catch (error) {
this.httpErrorHandle.httpStatusHandle(error) this.httpErrorHandle.httpStatusHandle(error)
@@ -329,8 +340,6 @@ export class ViewPublicationsPage implements OnInit {
} }
this.close(); this.close();
this.getActions.emit(); this.getActions.emit();
} }
// Do nothing // Do nothing
}); });
@@ -343,7 +352,7 @@ export class ViewPublicationsPage implements OnInit {
this.stopVideo(); this.stopVideo();
setTimeout(() => { setTimeout(()=> {
this.openPublicationDetails.emit({ DocumentId, ProcessId }); this.openPublicationDetails.emit({ DocumentId, ProcessId });
}, 200) }, 200)
@@ -370,12 +379,12 @@ export class ViewPublicationsPage implements OnInit {
stopVideo() { stopVideo() {
var videos = document.querySelectorAll('video'); var videos = document.querySelectorAll('video');
try { // Pause each video
// Pause each video videos.forEach(function (video) {
videos.forEach(function (video) { video.pause();
video.pause(); })
})
try {
this.videoElements.forEach(videoElement => { this.videoElements.forEach(videoElement => {
// You can access the native HTML video element using videoElement.nativeElement // You can access the native HTML video element using videoElement.nativeElement
@@ -385,20 +394,20 @@ export class ViewPublicationsPage implements OnInit {
// Do something with each video element // Do something with each video element
// console.log(video); // console.log(video);
}); });
} catch (e) {
} catch (error) {
console.log(error)
} }
} }
public onScroll(event): void { public onScroll(event): void {
if (this.lastScrollTop < event.detail.scrollTop) { if(this.lastScrollTop < event.detail.scrollTop) {
// console.log("scrolling down") // console.log("scrolling down")
} else { } else {
// console.log("scrolling up") // console.log("scrolling up")
} }
this.lastScrollTop = event.detail.scrollTop; this.lastScrollTop = event.detail.scrollTop;
} }
} }
@@ -1,25 +1,82 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MiddlewareServiceService } from "src/app/shared/API/middleware/middleware-service.service"; import { MiddlewareServiceService } from "src/app/shared/API/middleware/middleware-service.service";
import { ok, err } from 'neverthrow'; import { CMAPIAPIService } from "src/app/shared/API/CMAPI/cmapi-api.service";
import { ok, err, Result } from 'neverthrow';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { IuploadFileLK } from '../../API/middleware/interface';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class CMAPIService { export class CMAPIService {
constructor(public MiddlewareServiceService: MiddlewareServiceService) { constructor(
window["CMAPIService"] = this public MiddlewareServiceService: MiddlewareServiceService,
private CMAPIAPIService: CMAPIAPIService) {
window["CMAPIAPIRepository"] = this
} }
async FileContent({length, path, index, blobFile}) { async FileContent({length, path, index, base64}): Promise<Result<IuploadFileLK, "badRequest" | "other">> {
try { try {
const result = await this.MiddlewareServiceService.CMAPIFileContent({length, path, index, blobFile}).toPromise(); const result = await this.MiddlewareServiceService.CMAPIFileContent({length, path, index, base64}).toPromise();
return ok(result)
} catch (error) {
if(error.status >= 400 && error.status >= 499) {
return err("badRequest")
}
return err("other")
}
}
async RequestUpload(): Promise<Result<string, any>> {
try {
const result = await this.MiddlewareServiceService.CMAPIRequestUpload().toPromise();
return ok(result) return ok(result)
} catch (error) { } catch (error) {
return err(error) return err(error)
} }
}
async UploadStatus() {
try {
const result = await this.MiddlewareServiceService.CMAPIUploadStatus().toPromise();
return ok(result)
} catch (error) {
return err(error)
}
}
async ping() {
try {
await this.MiddlewareServiceService.tryToReachTheServer().toPromise();
return ok(true)
} catch (error) {
if(error.status == 0) {
return err(false)
}
return ok(true)
}
}
async getVideoHeader(url: string) {
try {
await this.CMAPIAPIService.getVideoHeader(url).toPromise()
return ok(true)
} catch(error) {
if(error.status == 405) {
return ok(true)
}
return err(false)
}
} }