mirror of
https://code.equilibrium.co.ao/ITO/doneit-web.git
synced 2026-04-18 20:47:54 +00:00
send audio as attachment
This commit is contained in:
@@ -0,0 +1,105 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { GenericResponse, RecordingData, VoiceRecorder } from 'capacitor-voice-recorder';
|
||||||
|
import { err, ok, Result } from 'neverthrow';
|
||||||
|
|
||||||
|
export enum StartRecordingResultError {
|
||||||
|
NoSpeaker,
|
||||||
|
NeedPermission,
|
||||||
|
alreadyRecording
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StopRecordingResultError {
|
||||||
|
haventStartYet,
|
||||||
|
NoValue,
|
||||||
|
UnknownError
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SpeakerService {
|
||||||
|
|
||||||
|
|
||||||
|
recording = false;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
|
||||||
|
async startRecording(): Promise<Result<true, StartRecordingResultError>> {
|
||||||
|
// Request audio recording permission
|
||||||
|
await VoiceRecorder.requestAudioRecordingPermission();
|
||||||
|
|
||||||
|
// Check if the device can record audio
|
||||||
|
const canRecord = await VoiceRecorder.canDeviceVoiceRecord();
|
||||||
|
if (!canRecord.value) {
|
||||||
|
return err(StartRecordingResultError.NoSpeaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the app has permission to record audio
|
||||||
|
const hasPermission = await VoiceRecorder.requestAudioRecordingPermission();
|
||||||
|
if (!hasPermission.value) {
|
||||||
|
return err(StartRecordingResultError.NeedPermission);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if recording is already in progress
|
||||||
|
if (this.recording) {
|
||||||
|
return err(StartRecordingResultError.alreadyRecording)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start recording
|
||||||
|
this.recording = true;
|
||||||
|
VoiceRecorder.startRecording();
|
||||||
|
return ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of a poorly structured startRecording method (commented out).
|
||||||
|
*
|
||||||
|
* - This example demonstrates improper chaining of promises and lack of proper error handling.
|
||||||
|
* - Avoid using this approach for better readability and maintainability.
|
||||||
|
*/
|
||||||
|
// bad code example
|
||||||
|
// async startRecording() {
|
||||||
|
// VoiceRecorder.requestAudioRecordingPermission();
|
||||||
|
// if (await VoiceRecorder.canDeviceVoiceRecord().then((result: GenericResponse) => { return result.value })) {
|
||||||
|
// if (await VoiceRecorder.requestAudioRecordingPermission().then((result: GenericResponse) => { return result.value })) {
|
||||||
|
// //if(await this.hasAudioRecordingPermission()){
|
||||||
|
// if (this.recording) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// this.recording = true;
|
||||||
|
// VoiceRecorder.startRecording()
|
||||||
|
// //}
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// return err('need Permission');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// return err('no speaker');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
async stopRecording(): Promise<Result<RecordingData, StopRecordingResultError>> {
|
||||||
|
if (!this.recording) {
|
||||||
|
return err(StopRecordingResultError.haventStartYet);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recording = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await VoiceRecorder.stopRecording();
|
||||||
|
|
||||||
|
if (result.value && result.value.recordDataBase64) {
|
||||||
|
const recordData = result.value.recordDataBase64;
|
||||||
|
return ok(result);
|
||||||
|
} else {
|
||||||
|
return err(StopRecordingResultError.NoValue);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Handle any unexpected errors that might occur during stopRecording
|
||||||
|
return err(StopRecordingResultError.UnknownError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -141,9 +141,9 @@
|
|||||||
está a escrever...
|
está a escrever...
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="width-100 pl-20 pr-20">
|
<div class="width-100 pl-20 pr-20">
|
||||||
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
|
<span >{{durationDisplay}}</span>
|
||||||
<div class=" audioDiv d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded">
|
<div class=" audioDiv d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded">
|
||||||
<div (click)="start(audioRecorded)" *ngIf="!isPlaying" > <ion-icon slot="icon-only" name="play"></ion-icon> </div>
|
<div (click)="start(audioRecordedSafe)" *ngIf="!isPlaying" > <ion-icon slot="icon-only" name="play"></ion-icon> </div>
|
||||||
<div (click)="togglePlayer(isPlaying)" *ngIf="isPlaying"> <ion-icon slot="icon-only" name="pause"></ion-icon> </div>
|
<div (click)="togglePlayer(isPlaying)" *ngIf="isPlaying"> <ion-icon slot="icon-only" name="pause"></ion-icon> </div>
|
||||||
<ion-range #range [(ngModel)]="audioProgress" max="100" (mouseup)="seek()"></ion-range>
|
<ion-range #range [(ngModel)]="audioProgress" max="100" (mouseup)="seek()"></ion-range>
|
||||||
</div>
|
</div>
|
||||||
@@ -189,13 +189,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<button class="btn-no-color" (click)="sendMessage()">
|
<div class="btn-send">
|
||||||
|
<button #recordbtn *ngIf="textField == '' && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
|
||||||
|
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
|
||||||
|
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="textField != ''" class="btn-no-color" (click)="sendMessage()">
|
||||||
|
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
||||||
|
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="textField == '' && lastAudioRecorded" class="btn-no-color" (click)="sendAudio(lastAudioRecorded)">
|
||||||
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
||||||
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ion-footer>
|
</ion-footer>
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import { ViewDocumentPage } from 'src/app/modals/view-document/view-document.pag
|
|||||||
import { ThemeService } from 'src/app/services/theme.service';
|
import { ThemeService } from 'src/app/services/theme.service';
|
||||||
import { ViewEventPage } from 'src/app/modals/view-event/view-event.page';
|
import { ViewEventPage } from 'src/app/modals/view-event/view-event.page';
|
||||||
import { Storage } from '@ionic/storage';
|
import { Storage } from '@ionic/storage';
|
||||||
// import { RochetChatConnectorService } from 'src/app/services/chat/rochet-chat-connector.service'
|
|
||||||
// simport { MessageService } from 'src/app/services/chat/message.service';
|
|
||||||
import { FileType } from 'src/app/models/fileType';
|
import { FileType } from 'src/app/models/fileType';
|
||||||
import { SearchPage } from 'src/app/pages/search/search.page';
|
import { SearchPage } from 'src/app/pages/search/search.page';
|
||||||
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
||||||
@@ -28,21 +26,17 @@ import { FileOpener } from '@awesome-cordova-plugins/file-opener/ngx';
|
|||||||
import { SessionStore } from 'src/app/store/session.service';
|
import { SessionStore } from 'src/app/store/session.service';
|
||||||
import { Howl } from 'howler';
|
import { Howl } from 'howler';
|
||||||
import { ViewMediaPage } from 'src/app/modals/view-media/view-media.page';
|
import { ViewMediaPage } from 'src/app/modals/view-media/view-media.page';
|
||||||
import { ChatMessageDebuggingPage } from 'src/app/shared/popover/chat-message-debugging/chat-message-debugging.page';
|
|
||||||
import { PermissionService } from 'src/app/services/permission.service';
|
import { PermissionService } from 'src/app/services/permission.service';
|
||||||
import { FileValidatorService } from "src/app/services/file/file-validator.service"
|
|
||||||
import { ChatPopoverPage } from '../../popover/chat-popover/chat-popover.page';
|
import { ChatPopoverPage } from '../../popover/chat-popover/chat-popover.page';
|
||||||
import { Observable as DexieObservable } from 'Dexie';
|
import { Observable as DexieObservable } from 'Dexie';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { MessageRepositoryService } from 'src/app/module/chat/data/repository/message-respository.service'
|
import { MessageRepositoryService } from 'src/app/module/chat/data/repository/message-respository.service'
|
||||||
import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service'
|
import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service'
|
||||||
import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
|
import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message';
|
||||||
import { MessageInputDTO } from 'src/app/module/chat/data/dto/message/messageInputDtO';
|
|
||||||
import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO';
|
import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO';
|
||||||
import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service';
|
import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service';
|
||||||
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
|
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
|
||||||
import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page';
|
import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page';
|
||||||
import { tap } from 'rxjs/operators';
|
|
||||||
import { MessageEntity } from 'src/app/module/chat/domain/entity/message';
|
import { MessageEntity } from 'src/app/module/chat/domain/entity/message';
|
||||||
import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/members';
|
import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/members';
|
||||||
import { TypingTable } from 'src/app/module/chat/infra/database/dexie/schema/typing';
|
import { TypingTable } from 'src/app/module/chat/infra/database/dexie/schema/typing';
|
||||||
@@ -52,7 +46,7 @@ import { CameraService } from 'src/app/infra/camera/camera.service'
|
|||||||
import { compressImageBase64 } from '../../../utils/imageCompressore';
|
import { compressImageBase64 } from '../../../utils/imageCompressore';
|
||||||
import { FilePickerWebService } from 'src/app/infra/file-picker/web/file-picker-web.service'
|
import { FilePickerWebService } from 'src/app/infra/file-picker/web/file-picker-web.service'
|
||||||
import { allowedDocExtension } from 'src/app/utils/allowedDocExtension';
|
import { allowedDocExtension } from 'src/app/utils/allowedDocExtension';
|
||||||
|
import { SpeakerService, StartRecordingResultError, StopRecordingResultError } from 'src/app/infra/speaker/speaker.service'
|
||||||
const IMAGE_DIR = 'stored-images';
|
const IMAGE_DIR = 'stored-images';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-messages',
|
selector: 'app-messages',
|
||||||
@@ -69,7 +63,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
dm: any;
|
dm: any;
|
||||||
userPresence = '';
|
userPresence = '';
|
||||||
dmUsers: any;
|
dmUsers: any;
|
||||||
checktimeOut: boolean;
|
|
||||||
downloadProgess = 0;
|
downloadProgess = 0;
|
||||||
|
|
||||||
@Input() roomId: string;
|
@Input() roomId: string;
|
||||||
@@ -95,17 +88,15 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
mesageItemDropdownOptions: boolean = false;
|
mesageItemDropdownOptions: boolean = false;
|
||||||
scrollToBottomBtn = false;
|
scrollToBottomBtn = false;
|
||||||
longPressActive = false;
|
longPressActive = false;
|
||||||
frameUrl: any;
|
|
||||||
downloadFile: string;
|
downloadFile: string;
|
||||||
massages = []
|
|
||||||
|
|
||||||
showAvatar = true;
|
showAvatar = true;
|
||||||
|
|
||||||
recording = false;
|
recording = false;
|
||||||
allowTyping = true;
|
allowTyping = true;
|
||||||
storedFileNames = [];
|
|
||||||
lastAudioRecorded = '';
|
lastAudioRecorded = '';
|
||||||
audioRecorded: any = "";
|
audioRecordedSafe: any = "";
|
||||||
|
audioRecordedDataUrl: any = "";
|
||||||
audioDownloaded: any = "";
|
audioDownloaded: any = "";
|
||||||
durationDisplay = '';
|
durationDisplay = '';
|
||||||
duration = 0;
|
duration = 0;
|
||||||
@@ -139,6 +130,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
selectedMessage: any = null;
|
selectedMessage: any = null;
|
||||||
emojis: string[] = ['😊', '😂', '❤️', '👍', '😢']; // Add more emojis as needed
|
emojis: string[] = ['😊', '😂', '❤️', '👍', '😢']; // Add more emojis as needed
|
||||||
totalMessage = 0
|
totalMessage = 0
|
||||||
|
recordData:RecordingData
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public popoverController: PopoverController,
|
public popoverController: PopoverController,
|
||||||
private modalController: ModalController,
|
private modalController: ModalController,
|
||||||
@@ -156,13 +149,13 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
private platform: Platform,
|
private platform: Platform,
|
||||||
private fileOpener: FileOpener,
|
private fileOpener: FileOpener,
|
||||||
public p: PermissionService,
|
public p: PermissionService,
|
||||||
private FileValidatorService: FileValidatorService,
|
|
||||||
private roomRepositoryService: RoomRepositoryService,
|
private roomRepositoryService: RoomRepositoryService,
|
||||||
private messageRepositoryService: MessageRepositoryService,
|
private messageRepositoryService: MessageRepositoryService,
|
||||||
private userTypingServiceRepository: UserTypingServiceRepository,
|
private userTypingServiceRepository: UserTypingServiceRepository,
|
||||||
private chatServiceService: ChatServiceService,
|
private chatServiceService: ChatServiceService,
|
||||||
private CameraService: CameraService,
|
private CameraService: CameraService,
|
||||||
private FilePickerWebService: FilePickerWebService
|
private FilePickerWebService: FilePickerWebService,
|
||||||
|
private SpeakerService: SpeakerService
|
||||||
) {
|
) {
|
||||||
// update
|
// update
|
||||||
this.checkAudioPermission()
|
this.checkAudioPermission()
|
||||||
@@ -288,7 +281,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
this.getChatMembers();
|
this.getChatMembers();
|
||||||
|
|
||||||
this.deleteRecording();
|
this.deleteRecording();
|
||||||
this.loadFiles();
|
// this.loadFiles();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +302,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
load = () => {
|
load = () => {
|
||||||
this.checktimeOut = true;
|
|
||||||
this.getChatMembers();
|
this.getChatMembers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,21 +328,13 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @HostListener('scroll', ['$event'])
|
|
||||||
// onScroll(event: any): void {
|
|
||||||
// // const scrollTop = event.target.scrollTop;
|
|
||||||
// // const scrollHeight = event.target.scrollHeight;
|
|
||||||
// // const clientHeight = event.target.clientHeight;
|
|
||||||
|
|
||||||
// // if (scrollTop === 0) {
|
|
||||||
// // console.log('load more')
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
// this.scrollChangeCallback = () => this.onContentScrolled(event);
|
// this.scrollChangeCallback = () => this.onContentScrolled(event);
|
||||||
// window.addEventListener('scroll', this.scrollChangeCallback, true);
|
// window.addEventListener('scroll', this.scrollChangeCallback, true);
|
||||||
}
|
}
|
||||||
|
ngOnDestroy() {
|
||||||
|
window.removeEventListener('scroll', this.scrollChangeCallback, true);
|
||||||
|
}
|
||||||
|
|
||||||
onContentScrolled(e) {
|
onContentScrolled(e) {
|
||||||
this.startPosition = e.srcElement.scrollTop;
|
this.startPosition = e.srcElement.scrollTop;
|
||||||
@@ -394,107 +378,90 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
})
|
})
|
||||||
const base64sound = audioFile.data;
|
const base64sound = audioFile.data;
|
||||||
const base64Response = await fetch(`data:audio/ogg;base64,${base64sound}`);
|
const base64Response = await fetch(`data:audio/ogg;base64,${base64sound}`);
|
||||||
this.audioRecorded = base64Response.url;
|
this.audioRecordedSafe = base64Response.url;
|
||||||
}
|
|
||||||
|
|
||||||
async loadFiles() {
|
|
||||||
try {
|
|
||||||
this.storage.get('fileName').then((fileName) => {
|
|
||||||
this.lastAudioRecorded = fileName;
|
|
||||||
})
|
|
||||||
|
|
||||||
this.storage.get('recordData').then((recordData) => {
|
|
||||||
|
|
||||||
if (recordData?.value?.recordDataBase64.includes('data:audio')) {
|
|
||||||
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData?.value?.recordDataBase64);
|
|
||||||
}
|
|
||||||
else if (recordData?.value?.mimeType && recordData?.value?.recordDataBase64) {
|
|
||||||
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData?.value?.recordDataBase64}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) { }
|
|
||||||
|
|
||||||
|
|
||||||
this.storage.get('recordData').then((recordData) => {
|
|
||||||
|
|
||||||
if (recordData?.value?.recordDataBase64?.includes('data:audio')) {
|
|
||||||
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
|
|
||||||
}
|
|
||||||
else if (recordData?.value?.mimeType && recordData?.value?.recordDataBase64) {
|
|
||||||
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async startRecording() {
|
async startRecording() {
|
||||||
VoiceRecorder.requestAudioRecordingPermission();
|
|
||||||
if (await VoiceRecorder.canDeviceVoiceRecord().then((result: GenericResponse) => { return result.value })) {
|
const start = await this.SpeakerService.startRecording()
|
||||||
if (await VoiceRecorder.requestAudioRecordingPermission().then((result: GenericResponse) => { return result.value })) {
|
|
||||||
//if(await this.hasAudioRecordingPermission()){
|
if(start.isOk()) {
|
||||||
if (this.recording) {
|
this.recording = true;
|
||||||
return;
|
this.calculateDuration();
|
||||||
}
|
} else if(start.error == StartRecordingResultError.NoSpeaker) {
|
||||||
this.recording = true;
|
|
||||||
VoiceRecorder.startRecording();
|
|
||||||
this.calculateDuration();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.toastService._badRequest('Para gravar uma mensagem de voz, permita o acesso do Gabinete Digital ao seu microfone.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.toastService._badRequest('Este dispositivo não tem capacidade para gravação de áudio!');
|
this.toastService._badRequest('Este dispositivo não tem capacidade para gravação de áudio!');
|
||||||
|
} else if (start.error == StartRecordingResultError.NeedPermission) {
|
||||||
|
this.toastService._badRequest('Para gravar uma mensagem de voz, permita o acesso do Gabinete Digital ao seu microfone.');
|
||||||
|
} else if(start.error == StartRecordingResultError.alreadyRecording) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stopRecording() {
|
async stopRecording() {
|
||||||
this.deleteRecording();
|
this.deleteRecording();
|
||||||
this.allowTyping = false;
|
this.allowTyping = false;
|
||||||
|
|
||||||
if (!this.recording) {
|
const stop = await this.SpeakerService.stopRecording()
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.recording = false;
|
|
||||||
VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
|
|
||||||
|
|
||||||
|
if(stop.isOk()) {
|
||||||
|
this.lastAudioRecorded = 'audio'
|
||||||
this.recording = false;
|
this.recording = false;
|
||||||
if (result.value && result.value.recordDataBase64) {
|
const recordData = stop.value
|
||||||
const recordData = result.value.recordDataBase64;
|
this.recordData = recordData
|
||||||
//
|
if (recordData.value.recordDataBase64.includes('data:audio')) {
|
||||||
const fileName = new Date().getTime() + ".mp3";
|
console.log({recordData})
|
||||||
//Save file
|
|
||||||
this.storage.set('fileName', fileName);
|
|
||||||
this.storage.set('recordData', result).then(() => {
|
|
||||||
|
|
||||||
})
|
this.audioRecordedDataUrl = recordData.value.recordDataBase64
|
||||||
|
this.audioRecordedSafe = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
|
||||||
}
|
}
|
||||||
})
|
else if (recordData.value.mimeType && recordData?.value?.recordDataBase64) {
|
||||||
setTimeout(async () => {
|
console.log({recordData})
|
||||||
this.loadFiles();
|
|
||||||
}, 1000);
|
this.audioRecordedDataUrl = `data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`
|
||||||
|
this.audioRecordedSafe = this.sanitiser.bypassSecurityTrustResourceUrl(this.audioRecordedDataUrl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (stop.error == StopRecordingResultError.haventStartYet) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendAudio(fileName) {
|
||||||
|
const roomId = this.roomId
|
||||||
|
//Converting base64 to blob
|
||||||
|
const encodedData = this.audioRecordedDataUrl;
|
||||||
|
|
||||||
|
const message = new MessageEntity();
|
||||||
|
message.roomId = this.roomId
|
||||||
|
|
||||||
|
message.sender = {
|
||||||
|
userPhoto: '',
|
||||||
|
wxeMail: SessionStore.user.Email,
|
||||||
|
wxFullName: SessionStore.user.FullName,
|
||||||
|
wxUserId: SessionStore.user.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
message.attachments = [{
|
||||||
|
file: encodedData,
|
||||||
|
fileName: "audio",
|
||||||
|
source: MessageAttachmentSource.Device,
|
||||||
|
fileType: MessageAttachmentFileType.Audio
|
||||||
|
}]
|
||||||
|
|
||||||
|
this.chatServiceService.sendMessage(message)
|
||||||
|
|
||||||
|
|
||||||
|
this.deleteRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteRecording() {
|
async deleteRecording() {
|
||||||
this.storage.remove('fileName');
|
|
||||||
this.storage.remove('recordData');
|
|
||||||
|
|
||||||
this.allowTyping = true;
|
this.allowTyping = true;
|
||||||
this.lastAudioRecorded = '';
|
this.lastAudioRecorded = '';
|
||||||
this.loadFiles();
|
this.audioRecordedSafe = ''
|
||||||
}
|
this.audioRecordedDataUrl = ''
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.checktimeOut = false;
|
|
||||||
window.removeEventListener('scroll', this.scrollChangeCallback, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
openBookMeetingComponent() {
|
|
||||||
let data = {
|
|
||||||
roomId: this.roomId,
|
|
||||||
members: []
|
|
||||||
}
|
|
||||||
this.openNewEventPage.emit(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showDateDuration(start: any) {
|
showDateDuration(start: any) {
|
||||||
@@ -525,18 +492,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
|
|
||||||
sendMessage() {
|
sendMessage() {
|
||||||
|
|
||||||
// const data: MessageInputDTO = {
|
|
||||||
// roomId: this.roomId,
|
|
||||||
// senderId: SessionStore.user.UserId,
|
|
||||||
// message: this.textField,
|
|
||||||
// messageType: 0,
|
|
||||||
// canEdit: false,
|
|
||||||
// oneShot:false,
|
|
||||||
// requireUnlock: false,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.messageRepositoryService.sendMessage(data)
|
|
||||||
|
|
||||||
const message = new MessageEntity();
|
const message = new MessageEntity();
|
||||||
message.message = this.textField
|
message.message = this.textField
|
||||||
message.roomId = this.roomId
|
message.roomId = this.roomId
|
||||||
@@ -554,46 +509,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async sendAudio(fileName) {
|
|
||||||
const roomId = this.roomId
|
|
||||||
let audioFile;
|
|
||||||
this.storage.get('recordData').then(async (recordData) => {
|
|
||||||
|
|
||||||
audioFile = recordData;
|
|
||||||
|
|
||||||
if (recordData?.value?.recordDataBase64?.includes('data:audio')) {
|
|
||||||
this.audioRecorded = recordData.value.recordDataBase64;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.audioRecorded = `data:${recordData.value.mimeType};base64,${recordData?.value?.recordDataBase64}`;
|
|
||||||
}
|
|
||||||
//Converting base64 to blob
|
|
||||||
const encodedData = btoa(this.audioRecorded);
|
|
||||||
const blob = this.fileService.base64toBlob(encodedData, recordData.value.mimeType)
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("blobFile", blob);
|
|
||||||
|
|
||||||
// this.ChatSystemService.getDmRoom(roomId).send({
|
|
||||||
// file: {
|
|
||||||
// "type": "application/audio",
|
|
||||||
// "msDuration": audioFile.value.msDuration,
|
|
||||||
// "mimeType": audioFile.value.mimeType,
|
|
||||||
// },
|
|
||||||
// attachments: [{
|
|
||||||
// "title": fileName,
|
|
||||||
// "title_link_download": true,
|
|
||||||
// "type": "audio"
|
|
||||||
// }],
|
|
||||||
// temporaryData: formData,
|
|
||||||
// attachmentsModelData: {
|
|
||||||
// fileBase64: encodedData,
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
});
|
|
||||||
this.deleteRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
async openViewDocumentModal(file: any) {
|
async openViewDocumentModal(file: any) {
|
||||||
let task = {
|
let task = {
|
||||||
@@ -644,31 +560,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
await modal.present();
|
await modal.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
getChatMembers() {
|
getChatMembers() {}
|
||||||
//
|
|
||||||
|
|
||||||
// this.showLoader = true;
|
|
||||||
// this.chatService.getMembers(this.roomId).subscribe(res => {
|
|
||||||
// this.members = res['members'];
|
|
||||||
// this.dmUsers = res['members'].filter(data => data.username != this.sessionStore.user.UserName)
|
|
||||||
// this.showLoader = false;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// this.dmUsers = this.ChatSystemService.getDmRoom(this.roomId).membersExcludeMe
|
|
||||||
}
|
|
||||||
|
|
||||||
async openMessagesOptions(ev: any) {
|
|
||||||
const popover = await this.popoverController.create({
|
|
||||||
component: MessagesOptionsPage,
|
|
||||||
componentProps: {
|
|
||||||
roomId: this.dm._id,
|
|
||||||
},
|
|
||||||
cssClass: 'messages-options',
|
|
||||||
event: ev,
|
|
||||||
translucent: true,
|
|
||||||
});
|
|
||||||
return await popover.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
async addContacts() {
|
async addContacts() {
|
||||||
const modal = await this.modalController.create({
|
const modal = await this.modalController.create({
|
||||||
@@ -678,24 +571,10 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
backdropDismiss: false
|
backdropDismiss: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
modal.onDidDismiss();
|
modal.onDidDismiss();
|
||||||
await modal.present();
|
await modal.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
async openChatOptions(ev: any) {
|
|
||||||
const popover = await this.popoverController.create({
|
|
||||||
component: ChatOptionsPopoverPage,
|
|
||||||
cssClass: 'chat-options-popover',
|
|
||||||
event: ev,
|
|
||||||
translucent: true
|
|
||||||
});
|
|
||||||
return await popover.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async _openMessagesOptions() {
|
async _openMessagesOptions() {
|
||||||
const enterAnimation = (baseEl: any) => {
|
const enterAnimation = (baseEl: any) => {
|
||||||
const backdropAnimation = this.animationController.create()
|
const backdropAnimation = this.animationController.create()
|
||||||
@@ -735,7 +614,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
modal.onDidDismiss().then(res => {
|
modal.onDidDismiss().then(res => {
|
||||||
|
|
||||||
if (res.data == 'leave') {
|
if (res.data == 'leave') {
|
||||||
this.getRoomInfo();
|
// this.getRoomInfo();
|
||||||
this.closeAllDesktopComponents.emit();
|
this.closeAllDesktopComponents.emit();
|
||||||
this.showEmptyContainer.emit();
|
this.showEmptyContainer.emit();
|
||||||
// this.ChatSystemService.hidingRoom(this.roomId).catch((error) => console.error(error));
|
// this.ChatSystemService.hidingRoom(this.roomId).catch((error) => console.error(error));
|
||||||
@@ -764,32 +643,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
this.openGroupContacts.emit(this.roomId);
|
this.openGroupContacts.emit(this.roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dataURItoBlob(dataURI) {
|
|
||||||
// convert base64 to raw binary data held in a string
|
|
||||||
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
|
|
||||||
var byteString = atob(dataURI.split(',')[1]);
|
|
||||||
|
|
||||||
// separate out the mime component
|
|
||||||
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
|
|
||||||
|
|
||||||
// write the bytes of the string to an ArrayBuffer
|
|
||||||
var ab = new ArrayBuffer(byteString.length);
|
|
||||||
|
|
||||||
// create a view into the buffer
|
|
||||||
var ia = new Uint8Array(ab);
|
|
||||||
|
|
||||||
// set the bytes of the buffer to the correct values
|
|
||||||
for (var i = 0; i < byteString.length; i++) {
|
|
||||||
ia[i] = byteString.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the ArrayBuffer to a blob, and you're done
|
|
||||||
var blob = new Blob([ab], { type: mimeString });
|
|
||||||
return blob;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async takePictureMobile() {
|
async takePictureMobile() {
|
||||||
|
|
||||||
const picture = await this.CameraService.takePicture({
|
const picture = await this.CameraService.takePicture({
|
||||||
@@ -834,44 +687,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async takePicture() {
|
|
||||||
|
|
||||||
const file = await Camera.getPhoto({
|
|
||||||
quality: 90,
|
|
||||||
// allowEditing: true,
|
|
||||||
resultType: CameraResultType.Base64,
|
|
||||||
source: CameraSource.Camera
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('FILE CHAT', file)
|
|
||||||
|
|
||||||
const imageBase64 = 'data:image/jpeg;base64,' + file.base64String
|
|
||||||
const blob = this.dataURItoBlob(imageBase64)
|
|
||||||
|
|
||||||
console.log(imageBase64)
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("blobFile", blob);
|
|
||||||
|
|
||||||
|
|
||||||
// this.ChatSystemService.getDmRoom(roomId).send({
|
|
||||||
// file: {
|
|
||||||
// "type": "application/img",
|
|
||||||
// "guid": ''
|
|
||||||
// },
|
|
||||||
// temporaryData: formData,
|
|
||||||
// attachments: [{
|
|
||||||
// "title": "file.jpg",
|
|
||||||
// "text": "description",
|
|
||||||
// "title_link_download": false,
|
|
||||||
// }],
|
|
||||||
// attachmentsModelData: {
|
|
||||||
// fileBase64: imageBase64,
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async addFile() {
|
async addFile() {
|
||||||
this.addFileToChat(['.doc', '.docx', '.pdf'], MessageAttachmentFileType.Doc)
|
this.addFileToChat(['.doc', '.docx', '.pdf'], MessageAttachmentFileType.Doc)
|
||||||
}
|
}
|
||||||
@@ -1018,51 +833,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getBase64(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = function () {
|
|
||||||
resolve(reader.result)
|
|
||||||
};
|
|
||||||
reader.onerror = function (error) {
|
|
||||||
console.log('Error: ', error);
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getFileReader(): FileReader {
|
|
||||||
const fileReader = new FileReader();
|
|
||||||
const zoneOriginalInstance = (fileReader as any)["__zone_symbol__originalInstance"];
|
|
||||||
return zoneOriginalInstance || fileReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBase64(file) {
|
|
||||||
var reader = this.getFileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
return new Promise(resolve => {
|
|
||||||
reader.onload = function () {
|
|
||||||
resolve(reader.result)
|
|
||||||
};
|
|
||||||
reader.onerror = function (error) {
|
|
||||||
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bookMeeting() {
|
|
||||||
let data = {
|
|
||||||
roomId: this.roomId,
|
|
||||||
members: []
|
|
||||||
}
|
|
||||||
this.openNewEventPage.emit(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
chatsend() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async _openChatOptions() {
|
async _openChatOptions() {
|
||||||
const roomId = this.roomId;
|
const roomId = this.roomId;
|
||||||
@@ -1141,15 +911,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pdfPreview() {
|
|
||||||
const options: DocumentViewerOptions = {
|
|
||||||
title: 'My App'
|
|
||||||
};
|
|
||||||
DocumentViewer.viewDocument
|
|
||||||
}
|
|
||||||
|
|
||||||
async audioPreview(msg) {
|
async audioPreview(msg) {
|
||||||
|
|
||||||
if (!msg.attachments[0].title_link || msg.attachments[0].title_link === null || msg.attachments[0].title_link === '') {
|
if (!msg.attachments[0].title_link || msg.attachments[0].title_link === null || msg.attachments[0].title_link === '') {
|
||||||
@@ -1314,68 +1075,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRoomInfo() {
|
|
||||||
// let room = await this.chatService.getRoomInfo(this.roomId).toPromise();
|
|
||||||
// this.room = room['room'];
|
|
||||||
// if (this.room.name) {
|
|
||||||
// try {
|
|
||||||
// this.roomName = this.room.name.split('-').join(' ');
|
|
||||||
// } catch (error) {
|
|
||||||
// this.roomName = this.room.name;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// if (SessionStore.user.ChatData.data.userId == this.room.u._id) {
|
|
||||||
// this.isAdmin = true
|
|
||||||
// } else {
|
|
||||||
// this.isAdmin = false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (this.room.customFields.countDownDate) {
|
|
||||||
// this.roomCountDownDate = this.room.customFields.countDownDate;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async compressImageBase64(base64String: string, maxWidth: number, maxHeight: number, quality: number): Promise<string> {
|
|
||||||
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);
|
|
||||||
resolve(compressedBase64);
|
|
||||||
};
|
|
||||||
|
|
||||||
image.onerror = (error) => {
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user