mirror of
https://code.equilibrium.co.ao/ITO/doneit-web.git
synced 2026-04-18 12:37:53 +00:00
allow to send files to chat
This commit is contained in:
+1
-1
@@ -88,7 +88,7 @@ cypress/videos
|
||||
|
||||
src/app/models/beast-orm-pro.ts
|
||||
|
||||
|
||||
doc/TypeDoc
|
||||
src/app/pipes/process.service.spec.ts
|
||||
src/app/pipes/process.service.ts
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html><html class="default" lang="en"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>JSFileToBase64 | gabinete-digital</title><meta name="description" content="Documentation for gabinete-digital"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search" data-base=".."><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">gabinete-digital</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../modules.html">gabinete-digital</a></li><li><a href="JSFileToBase64.html">JSFileToBase64</a></li></ul><h1>Function JSFileToBase64</h1></div><section class="tsd-panel"><ul class="tsd-signatures"><li class="tsd-signature tsd-anchor-link"><a id="JSFileToBase64" class="tsd-anchor"></a><span class="tsd-kind-call-signature">JSFile<wbr/>To<wbr/>Base64</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">file</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">Result</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">></span><span class="tsd-signature-symbol">></span><a href="#JSFileToBase64" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></li><li class="tsd-description"><div class="tsd-comment tsd-typography"><p>Converts a <code>File</code> object to a Base64 encoded string.</p>
|
||||
</div><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">file</span>: <span class="tsd-signature-type">File</span></span><div class="tsd-comment tsd-typography"><p>The file to be converted.</p>
|
||||
</div><div class="tsd-comment tsd-typography"></div></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">Result</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">></span><span class="tsd-signature-symbol">></span></h4><p>A promise that resolves with a <code>Result</code> object containing either the Base64 encoded string or an error.</p>
|
||||
<div class="tsd-comment tsd-typography"></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://bitbucket.org/equilibriumito/gabinete-digital-fo/src/6cbd8d903c941c7bd6a270a4c51e608bee542f5a/src/app/utils/ToBase64.ts#lines-18">ToBase64.ts:18</a></li></ul></aside></li></ul></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1"></use></svg><span>gabinete-digital</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base=".."><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
||||
<div class="tsd-comment tsd-typography"></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://bitbucket.org/equilibriumito/gabinete-digital-fo/src/28bc141d389bc398728ff4bb15cacd51af677e25/src/app/utils/ToBase64.ts#lines-18">ToBase64.ts:18</a></li></ul></aside></li></ul></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1"></use></svg><span>gabinete-digital</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base=".."><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
||||
|
||||
@@ -77,7 +77,7 @@ export class AppComponent {
|
||||
if(this.platform.is('ios')){
|
||||
this.screenOrientation.lock('portrait')
|
||||
} else {
|
||||
window.screen.orientation.lock('portrait');
|
||||
(window.screen.orientation as any).lock('portrait');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CameraService } from './camera.service';
|
||||
|
||||
describe('CameraService', () => {
|
||||
let service: CameraService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(CameraService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
||||
import { err, ok } from 'neverthrow';
|
||||
|
||||
|
||||
type takePictureParams = {
|
||||
quality?: number
|
||||
cameraResultType: CameraResultType
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CameraService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
||||
async takePicture({quality = 90, cameraResultType }: takePictureParams) {
|
||||
|
||||
try {
|
||||
const file = await Camera.getPhoto({
|
||||
quality: quality,
|
||||
// allowEditing: true,
|
||||
resultType: cameraResultType,
|
||||
source: CameraSource.Camera
|
||||
});
|
||||
|
||||
return ok(file)
|
||||
} catch (e) {
|
||||
return err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
||||
import { err, ok, Result } from 'neverthrow';
|
||||
import { FileType } from 'src/app/models/fileType';
|
||||
|
||||
type PickPictureParams = {
|
||||
quality?: number,
|
||||
cameraResultType?: CameraResultType
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@@ -8,7 +15,7 @@ export class FilePickerWebService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
getFileFromDevice(types: typeof FileType[]): Promise<File> {
|
||||
getFileFromDevice(types: typeof FileType[]): Promise<Result<File, any>> {
|
||||
let input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = types.join(', ')
|
||||
@@ -18,9 +25,24 @@ export class FilePickerWebService {
|
||||
return new Promise((resolve, reject)=>{
|
||||
input.onchange = async () => {
|
||||
const file = Array.from(input.files)
|
||||
resolve(file[0] as File);
|
||||
resolve(ok(file[0] as File));
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
async getPicture({quality = 90, cameraResultType =CameraResultType.DataUrl }: PickPictureParams) {
|
||||
try {
|
||||
const file = await Camera.getPhoto({
|
||||
quality: quality,
|
||||
// allowEditing: true,
|
||||
resultType: cameraResultType,
|
||||
source: CameraSource.Photos
|
||||
});
|
||||
|
||||
return ok(file)
|
||||
} catch (e) {
|
||||
return err(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export class MessageEntity implements Message {
|
||||
attachments: {
|
||||
fileType: MessageAttachmentFileType,
|
||||
source: MessageAttachmentSource,
|
||||
file: string,
|
||||
file?: string,
|
||||
fileName: string,
|
||||
applicationId?: string,
|
||||
docId?: string
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
<ion-fab-button title="Adicionar Documento" (click)="addFile()" color="light">
|
||||
<ion-icon name="document"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button title="Anexar Fotografia" (click)="addImage()" color="light">
|
||||
<ion-fab-button title="Anexar Fotografia" (click)="pickPicture()" color="light">
|
||||
<ion-icon name="image"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button title="Tirar Fotografia" (click)="takePictureMobile()" color="light">
|
||||
|
||||
@@ -48,7 +48,10 @@ import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/mem
|
||||
import { TypingTable } from 'src/app/module/chat/infra/database/dexie/schema/typing';
|
||||
import { MessageAttachmentFileType, MessageAttachmentSource } from 'src/app/module/chat/data/dto/message/messageOutputDTO';
|
||||
import { JSFileToBase64 } from 'src/app/utils/ToBase64';
|
||||
|
||||
import { CameraService } from 'src/app/infra/camera/camera.service'
|
||||
import { compressImageBase64 } from '../../../utils/imageCompressore';
|
||||
import { FilePickerWebService } from 'src/app/infra/file-picker/web/file-picker-web.service'
|
||||
import { allowedDocExtension } from 'src/app/utils/allowedDocExtension';
|
||||
|
||||
const IMAGE_DIR = 'stored-images';
|
||||
@Component({
|
||||
@@ -158,6 +161,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
private messageRepositoryService: MessageRepositoryService,
|
||||
private userTypingServiceRepository: UserTypingServiceRepository,
|
||||
private chatServiceService: ChatServiceService,
|
||||
private CameraService: CameraService,
|
||||
private FilePickerWebService: FilePickerWebService
|
||||
) {
|
||||
// update
|
||||
this.checkAudioPermission()
|
||||
@@ -679,17 +684,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
await modal.present();
|
||||
}
|
||||
|
||||
openSendMessageOptions(ev?: any) {
|
||||
if (window.innerWidth < 701) {
|
||||
|
||||
this.openChatOptions(ev);
|
||||
}
|
||||
else {
|
||||
|
||||
this._openChatOptions();
|
||||
}
|
||||
}
|
||||
|
||||
async openChatOptions(ev: any) {
|
||||
const popover = await this.popoverController.create({
|
||||
component: ChatOptionsPopoverPage,
|
||||
@@ -798,57 +792,50 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
|
||||
async takePictureMobile() {
|
||||
|
||||
const picture = await this.CameraService.takePicture({
|
||||
cameraResultType: CameraResultType.DataUrl,
|
||||
quality: 90
|
||||
})
|
||||
|
||||
const roomId = this.roomId
|
||||
if(picture.isOk()) {
|
||||
const file = picture.value
|
||||
|
||||
const file = await Camera.getPhoto({
|
||||
quality: 90,
|
||||
// allowEditing: true,
|
||||
resultType: CameraResultType.Base64,
|
||||
source: CameraSource.Camera
|
||||
});
|
||||
console.log('Selected: ', file)
|
||||
var base64 = 'data:image/jpeg;base64,' + file.base64String
|
||||
const compressedImage = await this.compressImageBase64(
|
||||
base64,
|
||||
800, // maxWidth
|
||||
800, // maxHeight
|
||||
0.9 // quality
|
||||
).then((picture) => {
|
||||
const compressedImage = await compressImageBase64(
|
||||
file.dataUrl,
|
||||
800, // maxWidth
|
||||
800, // maxHeight
|
||||
0.9 // quality
|
||||
)
|
||||
|
||||
base64 = picture
|
||||
});
|
||||
if(compressedImage.isOk()) {
|
||||
|
||||
const message = new MessageEntity();
|
||||
message.roomId = this.roomId
|
||||
|
||||
const blob = this.dataURItoBlob(base64)
|
||||
message.sender = {
|
||||
userPhoto: '',
|
||||
wxeMail: SessionStore.user.Email,
|
||||
wxFullName: SessionStore.user.FullName,
|
||||
wxUserId: SessionStore.user.UserId
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("blobFile", blob);
|
||||
message.attachments = [{
|
||||
file: compressedImage.value,
|
||||
fileName: "foto",
|
||||
source: MessageAttachmentSource.Device,
|
||||
fileType: MessageAttachmentFileType.Image
|
||||
}]
|
||||
|
||||
// this.ChatSystemService.getDmRoom(roomId).send({
|
||||
// file: {
|
||||
// "type": "application/img",
|
||||
// "guid": '',
|
||||
// },
|
||||
// temporaryData: formData,
|
||||
// attachments: [{
|
||||
// "title": file.path,
|
||||
// // "image_url": "",
|
||||
// //"image_url": 'data:image/jpeg;base64,' + file.base64String,
|
||||
// "text": "description",
|
||||
// "title_link_download": false,
|
||||
// }],
|
||||
// attachmentsModelData: {
|
||||
// fileBase64: base64,
|
||||
// }
|
||||
// })
|
||||
this.chatServiceService.sendMessage(message)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async takePicture() {
|
||||
|
||||
const roomId = this.roomId
|
||||
|
||||
const file = await Camera.getPhoto({
|
||||
quality: 90,
|
||||
// allowEditing: true,
|
||||
@@ -885,10 +872,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
|
||||
}
|
||||
|
||||
async addImage() {
|
||||
this.addFileToChatMobile(['image/apng', 'image/jpeg', 'image/png'])
|
||||
}
|
||||
|
||||
async addFile() {
|
||||
this.addFileToChat(['.doc', '.docx', '.pdf'], MessageAttachmentFileType.Doc)
|
||||
}
|
||||
@@ -907,29 +890,32 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
modal.onDidDismiss().then(async res => {
|
||||
|
||||
const data = res.data;
|
||||
const roomId = this.roomId
|
||||
|
||||
if (data.selected) {
|
||||
|
||||
// this.ChatSystemService.getDmRoom(roomId).send({
|
||||
// file: {
|
||||
// "name": res.data.selected.Assunto,
|
||||
// "type": "application/webtrix",
|
||||
// "ApplicationId": res.data.selected.ApplicationType,
|
||||
// "DocId": res.data.selected.Id,
|
||||
// "Assunto": res.data.selected.Assunto,
|
||||
// },
|
||||
// temporaryData: res,
|
||||
// attachments: [{
|
||||
// "title": res.data.selected.Assunto,
|
||||
// "description": res.data.selected.DocTypeDesc,
|
||||
// "title_link_download": true,
|
||||
// "type": "webtrix",
|
||||
// "text": res.data.selected.DocTypeDesc,
|
||||
// "thumb_url": "https://static.ichimura.ed.jp/uploads/2017/10/pdf-icon.png",
|
||||
// }],
|
||||
// })
|
||||
// "title": res.data.selected.Assunto,
|
||||
// "description": res.data.selected.DocTypeDesc,
|
||||
|
||||
const message = new MessageEntity();
|
||||
message.message = this.textField
|
||||
message.roomId = this.roomId
|
||||
|
||||
message.sender = {
|
||||
userPhoto: '',
|
||||
wxeMail: SessionStore.user.Email,
|
||||
wxFullName: SessionStore.user.FullName,
|
||||
wxUserId: SessionStore.user.UserId
|
||||
}
|
||||
message.attachments = [{
|
||||
fileName: res.data.selected.Assunto,
|
||||
source: MessageAttachmentSource.Webtrix,
|
||||
fileType: MessageAttachmentFileType.Doc,
|
||||
applicationId: res.data.selected.ApplicationType,
|
||||
docId: res.data.selected.Id,
|
||||
}]
|
||||
|
||||
this.chatServiceService.sendMessage(message)
|
||||
this.textField = ''
|
||||
|
||||
}
|
||||
});
|
||||
@@ -937,58 +923,48 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
await modal.present();
|
||||
}
|
||||
|
||||
async addFileToChatMobile(types: typeof FileType[]) {
|
||||
const roomId = this.roomId
|
||||
async pickPicture() {
|
||||
|
||||
const file = await Camera.getPhoto({
|
||||
quality: 90,
|
||||
// allowEditing: true,
|
||||
resultType: CameraResultType.Base64,
|
||||
source: CameraSource.Photos
|
||||
});
|
||||
const file = await this.FilePickerWebService.getPicture({
|
||||
cameraResultType: CameraResultType.Base64
|
||||
})
|
||||
|
||||
//const imageData = await this.fileToBase64Service.convert(file)
|
||||
//
|
||||
console.log('Selected: ', file)
|
||||
var base64 = 'data:image/jpeg;base64,' + file.base64String
|
||||
if (file.format == "jpeg" || file.format == "png" || file.format == "gif") {
|
||||
if(file.isOk()) {
|
||||
|
||||
const compressedImage = await this.compressImageBase64(
|
||||
base64,
|
||||
800, // maxWidth
|
||||
800, // maxHeight
|
||||
0.9 // quality
|
||||
).then((picture) => {
|
||||
var base64 = 'data:image/jpeg;base64,' + file.value.base64String
|
||||
if (file.value.format == "jpeg" || file.value.format == "png" || file.value.format == "gif") {
|
||||
|
||||
base64 = picture
|
||||
});
|
||||
const compressedImage = await compressImageBase64(
|
||||
base64,
|
||||
800, // maxWidth
|
||||
800, // maxHeight
|
||||
0.9 // quality
|
||||
)
|
||||
|
||||
const response = await fetch(base64);
|
||||
const blob = await response.blob();
|
||||
if(compressedImage.isOk()) {
|
||||
|
||||
console.log(base64)
|
||||
const message = new MessageEntity();
|
||||
message.roomId = this.roomId
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("blobFile", blob);
|
||||
message.sender = {
|
||||
userPhoto: '',
|
||||
wxeMail: SessionStore.user.Email,
|
||||
wxFullName: SessionStore.user.FullName,
|
||||
wxUserId: SessionStore.user.UserId
|
||||
}
|
||||
|
||||
// this.ChatSystemService.getDmRoom(roomId).send({
|
||||
// file: {
|
||||
// "type": "application/img",
|
||||
// "guid": ''
|
||||
// },
|
||||
// temporaryData: formData,
|
||||
// attachments: [{
|
||||
// "title": file.path,
|
||||
// //"image_url": 'data:image/jpeg;base64,' + file.base64String,
|
||||
// "text": "description",
|
||||
// "title_link_download": false,
|
||||
// }],
|
||||
// attachmentsModelData: {
|
||||
// fileBase64: base64,
|
||||
// }
|
||||
// })
|
||||
message.attachments = [{
|
||||
file: compressedImage.value,
|
||||
fileName: "foto",
|
||||
source: MessageAttachmentSource.Device,
|
||||
fileType: MessageAttachmentFileType.Image
|
||||
}]
|
||||
|
||||
this.chatServiceService.sendMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1003,20 +979,16 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
|
||||
async addFileToChat(types: typeof FileType[], attachmentFileType:MessageAttachmentFileType) {
|
||||
|
||||
const file = await this.fileService.getFileFromDevice(types);
|
||||
const file = await this.FilePickerWebService.getFileFromDevice(types);
|
||||
if(file.isOk()) {
|
||||
|
||||
if (file.type == 'application/pdf' || file.type == 'application/doc' || file.type == 'application/docx' ||
|
||||
file.type == 'application/xls' || file.type == 'application/xlsx' || file.type == 'application/ppt' ||
|
||||
file.type == 'application/pptx' || file.type == 'application/txt') {
|
||||
const fileExtension = await allowedDocExtension(file.value.type)
|
||||
|
||||
console.log('FILE rigth?', file)
|
||||
if(fileExtension.isOk()) {
|
||||
|
||||
const fileName = file.name
|
||||
console.log('FILE rigth?', file)
|
||||
|
||||
const FilenameValidation = this.FileValidatorService.fileNameValidation(fileName)
|
||||
|
||||
if (FilenameValidation.isOk) {
|
||||
let fileBase64 = await JSFileToBase64(file);
|
||||
let fileBase64 = await JSFileToBase64(file.value);
|
||||
|
||||
if(fileBase64.isOk()) {
|
||||
|
||||
@@ -1032,7 +1004,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
|
||||
message.attachments = [{
|
||||
file: fileBase64.value,
|
||||
fileName: file.name,
|
||||
fileName: file.value.name,
|
||||
source: MessageAttachmentSource.Device,
|
||||
fileType: MessageAttachmentFileType.Doc
|
||||
}]
|
||||
@@ -1043,9 +1015,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
} else {
|
||||
this.toastService._badRequest("Ficheiro inválido")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getBase64(file) {
|
||||
@@ -1151,7 +1121,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
}
|
||||
else if (res['data'] == 'add-picture') {
|
||||
|
||||
this.addImage()
|
||||
this.pickPicture()
|
||||
|
||||
}
|
||||
else if (res['data'] == 'add-document') {
|
||||
@@ -1371,7 +1341,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
|
||||
async compressImageBase64(base64String: string, maxWidth: number, maxHeight: number, quality: number): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new (window as any).Image();
|
||||
const image = new Image();
|
||||
image.src = base64String;
|
||||
|
||||
image.onload = async () => {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { err, ok } from "neverthrow"
|
||||
|
||||
export function allowedDocExtension(type: string) {
|
||||
if (type == 'application/pdf' || type == 'application/doc' || type == 'application/docx' ||
|
||||
type == 'application/xls' || type == 'application/xlsx' || type == 'application/ppt' ||
|
||||
type == 'application/pptx' || type == 'application/txt') {
|
||||
|
||||
return ok(true)
|
||||
} else {
|
||||
return err(false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { err, ok, Result } from "neverthrow";
|
||||
|
||||
/**
|
||||
* Compresses an image represented as a Base64 string.
|
||||
*
|
||||
* This function resizes the image to fit within the specified maximum width and height while maintaining the aspect ratio.
|
||||
* The image is then compressed to a JPEG format with the given quality level.
|
||||
*
|
||||
* @param base64String - The Base64 string of the image to be compressed.
|
||||
* @param maxWidth - The maximum width of the compressed image. The aspect ratio is preserved.
|
||||
* @param maxHeight - The maximum height of the compressed image. The aspect ratio is preserved.
|
||||
* @param quality - The quality of the compressed image, ranging from 0 to 1, where 1 is the best quality.
|
||||
*
|
||||
* @returns A Promise that resolves to a `Result` containing either:
|
||||
* - `ok` with the compressed image as a Base64 string, or
|
||||
* - `err` with an error if the image fails to load or compress.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* compressImageBase64('data:image/png;base64,...', 800, 600, 0.8)
|
||||
* .then(result => {
|
||||
* if (result.isOk()) {
|
||||
* console.log('Compressed image:', result.value);
|
||||
* } else {
|
||||
* console.error('Error compressing image:', result.error);
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function compressImageBase64(base64String: string, maxWidth: number, maxHeight: number, quality: number): Promise<Result<string, any>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.src = base64String;
|
||||
|
||||
image.onload = async () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
let newWidth = image.width;
|
||||
let newHeight = image.height;
|
||||
|
||||
if (newWidth > maxWidth) {
|
||||
newHeight *= maxWidth / newWidth;
|
||||
newWidth = maxWidth;
|
||||
}
|
||||
|
||||
if (newHeight > maxHeight) {
|
||||
newWidth *= maxHeight / newHeight;
|
||||
newHeight = maxHeight;
|
||||
}
|
||||
|
||||
canvas.width = newWidth;
|
||||
canvas.height = newHeight;
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
context?.drawImage(image, 0, 0, newWidth, newHeight);
|
||||
|
||||
const compressedBase64 = canvas.toDataURL('image/jpeg', quality);
|
||||
|
||||
// Calculate the compression percentage
|
||||
const originalSize = base64String.length;
|
||||
const compressedSize = compressedBase64.length;
|
||||
const compressionPercentage = ((originalSize - compressedSize) / originalSize) * 100;
|
||||
|
||||
console.log(`Compression achieved: ${compressionPercentage.toFixed(2)}%`);
|
||||
|
||||
resolve(ok(compressedBase64));
|
||||
};
|
||||
|
||||
image.onerror = (error) => {
|
||||
resolve(err(error));
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user