update file upload & download

This commit is contained in:
Chneemann 2024-06-12 20:42:23 +02:00
parent 1a3f4b8989
commit cc9377290f
12 changed files with 97 additions and 176 deletions

View file

@ -13,7 +13,7 @@ import { UserService } from '../../../service/user.service';
import { SingleChatComponent } from '../single-chat/single-chat.component';
import { ChatMsgBoxComponent } from '../chat-msg-box/chat-msg-box.component';
import { CommonModule } from '@angular/common';
import { DownloadFilesService } from '../../../service/download-files.service';
import { DownloadFilesService } from '../../../service/files.service';
import { ChannelService } from '../../../service/channel.service';
import { InfoComponent } from '../info/info.component';
@ -30,7 +30,7 @@ import { InfoComponent } from '../info/info.component';
templateUrl: './chat-content.component.html',
styleUrl: './chat-content.component.scss',
})
export class ChatContentComponent implements AfterViewInit, AfterViewChecked {
export class ChatContentComponent implements AfterViewInit {
@Input() currentChannel: string = '';
@Input() isPrivatChannel: boolean = false;
@Input() isSearchChannel: boolean = false;
@ -46,20 +46,11 @@ export class ChatContentComponent implements AfterViewInit, AfterViewChecked {
private chatService: ChatService,
private userService: UserService,
public channelService: ChannelService,
private downloadFilesService: DownloadFilesService,
private renderer: Renderer2
) {}
ngAfterViewInit() {
this.scrollToBottom();
this.checkIfLoadedFirebaseFiles();
}
ngAfterViewChecked() {
if (this.filesLoaded) {
this.scrollToBottom();
this.filesLoaded = false;
}
}
/**
@ -73,17 +64,6 @@ export class ChatContentComponent implements AfterViewInit, AfterViewChecked {
}
}
/**
* Checks whether Firebase files have been loaded from the server
*/
checkIfLoadedFirebaseFiles() {
this.downloadFilesService.downloadedFiles.subscribe((files) => {
if (files.length > 0) {
this.filesLoaded = true;
}
});
}
/**
* Scrolls to the bottom of the message body element.
*/

View file

@ -102,7 +102,7 @@
(click)="sendMessage()"
/>
}
<!--- show chnnels or users by pressing @ or #-->
<!--- show channels or users by pressing @ or #-->
@if (openSmallWindow) {
<div class="filteredElementWindow2">
@if (showChannels) { @for (i of checkIfUserHasAccessToChannel(); track

View file

@ -10,7 +10,7 @@ import {
import { FormsModule } from '@angular/forms';
import { PickerComponent } from '@ctrl/ngx-emoji-mart';
import { Firestore, addDoc, collection } from '@angular/fire/firestore';
import { DownloadFilesService } from '../../../service/download-files.service';
import { DownloadFilesService } from '../../../service/files.service';
import { UserService } from '../../../service/user.service';
import { EmojiPickerComponent } from '../../../shared/components/emoji-picker/emoji-picker.component';
import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component';

View file

@ -1,9 +1,8 @@
@if(imageUrl) {
<div class="files">
<div class="filesView">
@if (['png', 'jpg', 'jpeg', 'gif'].includes(getFileType(imageUrl))) {
@if (['png', 'jpg', 'jpeg', 'gif'].includes(getFileType(filePath))) {
<img
src="{{ imageUrl }}"
src="{{ filePath }}"
alt="image"
[ngStyle]="{
height:
@ -11,13 +10,13 @@
? '5vw'
: '7.5vw'
}"
(click)="showOverlay(imageUrl)"
(click)="showOverlay(filePath)"
/>
} @if (['pdf', 'doc', 'txt'].includes(getFileType(imageUrl))) {
<a href="{{ imageUrl }}" target="_blank">
} @if (['pdf', 'doc', 'txt'].includes(getFileType(filePath))) {
<a href="{{ filePath }}" target="_blank">
<img
class="otherFiles"
src="./assets/img/attachments/{{ getFileType(imageUrl) }}.png"
src="./assets/img/attachments/{{ getFileType(filePath) }}.png"
alt="image"
[ngStyle]="{
height:
@ -26,11 +25,11 @@
: '5vw'
}"
/></a>
} @if (['mp3', 'wav', 'wma'].includes(getFileType(imageUrl))) {
} @if (['mp3', 'wav', 'wma'].includes(getFileType(filePath))) {
<audio
controls
preload="auto"
src="{{ imageUrl }}"
src="{{ filePath }}"
[ngStyle]="{
width:
openOnSecondaryChat && viewWidth >= RESPONSIVE_THRESHOLD
@ -38,10 +37,10 @@
: ''
}"
></audio>
}@if (getFileType(imageUrl) === 'mp4') {
<div (click)="showOverlay(imageUrl)">
}@if (getFileType(filePath) === 'mp4') {
<div (click)="showOverlay(filePath)">
<video
src="{{ imageUrl }}"
src="{{ filePath }}"
alt="video"
[ngStyle]="{
height:
@ -54,4 +53,3 @@
}
</div>
</div>
}

View file

@ -1,6 +1,6 @@
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { DownloadFilesService } from '../../../../service/download-files.service';
import { DownloadFilesService } from '../../../../service/files.service';
import { OverlayService } from '../../../../service/overlay.service';
import { OverlayComponent } from '../../../../shared/components/overlay/overlay.component';
import { SharedService } from '../../../../service/shared.service';
@ -18,7 +18,6 @@ export class AttachmentsComponent {
@Input() openOnSecondaryChat: boolean = false;
@Input() viewWidth: number = 0;
loadingUrl: string = './../../../assets/img/loading.svg';
imageUrl: string | null = '';
constructor(
public downloadFilesService: DownloadFilesService,
@ -28,14 +27,6 @@ export class AttachmentsComponent {
RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD;
async ngOnInit() {
if (this.filePath) {
this.imageUrl = await this.downloadFilesService.downloadFiles(
this.filePath
);
}
}
// Type of files:
// Img: PNG, GIF, JPG, JPEG
// Files: PDF, DOC, TXT

View file

@ -6,7 +6,7 @@ import { FormsModule, NgForm } from '@angular/forms';
import { ChatService } from '../../../../service/chat.service';
import { PickerComponent } from '@ctrl/ngx-emoji-mart';
import { SmallBtnComponent } from '../../../../shared/components/small-btn/small-btn.component';
import { DownloadFilesService } from '../../../../service/download-files.service';
import { DownloadFilesService } from '../../../../service/files.service';
import { EmojiPickerComponent } from '../../../../shared/components/emoji-picker/emoji-picker.component';
import { UserService } from '../../../../service/user.service';
import { TranslateModule } from '@ngx-translate/core';

View file

@ -89,12 +89,12 @@
<span>{{ "single-chat.edit" | translate }}</span>
}
</div>
@if(filePath) {
@if(chat.attachments) {
<app-attachments
[chatId]="chat.id"
[openOnSecondaryChat]="openOnSecondaryChat"
[viewWidth]="viewWidth"
[filePath]="filePath"
[filePath]="chat.attachments"
></app-attachments>
}
</div>

View file

@ -4,7 +4,7 @@ import { Chat, ChatAnswers } from '../../../interface/chat.interface';
import { ChatContentComponent } from '../chat-content/chat-content.component';
import { CommonModule, NgSwitchCase } from '@angular/common';
import { ChatService } from '../../../service/chat.service';
import { DownloadFilesService } from '../../../service/download-files.service';
import { DownloadFilesService } from '../../../service/files.service';
import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer';
import { OptionsMenuComponent } from './options-menu/options-menu.component';
import { AttachmentsComponent } from './attachments/attachments.component';
@ -63,16 +63,6 @@ export class SingleChatComponent {
public downloadFilesService: DownloadFilesService
) {}
ngOnInit() {
this.checkChatHasFiles();
}
async checkChatHasFiles() {
this.filePath = await this.downloadFilesService.checkChatHasFiles(
this.chat.id
);
}
/**
* Emits a signal to edit a message.
* @param {boolean} variable - The value indicating whether the message edit form should be open or not.

View file

@ -1,10 +1,12 @@
export interface Chat {
id: string;
userId: string;
chatId: string;
channelId: string;
message: string;
edited: boolean;
publishedTimestamp: number;
attachments: string;
}
export interface ChatAnswers {
@ -14,6 +16,7 @@ export interface ChatAnswers {
edited: boolean;
publishedTimestamp: number;
userId: string;
attachments: string;
}
export interface ChatReactions {

View file

@ -11,6 +11,12 @@ import {
updateDoc,
} from '@angular/fire/firestore';
import { Chat, ChatAnswers, ChatReactions } from '../interface/chat.interface';
import {
getDownloadURL,
getStorage,
ref,
uploadBytes,
} from '@angular/fire/storage';
@Injectable({
providedIn: 'root',
@ -26,6 +32,7 @@ export class ChatService implements OnDestroy {
getChannelId: string = '';
getPrvChatId: string = '';
inputValue: string = '';
fileSrc: string = '';
unsubChat;
unsubChatAnswers;
@ -101,6 +108,14 @@ export class ChatService implements OnDestroy {
});
}
async updateChatFile(chatId: string, chatFile: string) {
await updateDoc(doc(collection(this.firestore, 'chats'), chatId), {
attachments: chatFile,
}).catch((err) => {
console.error(err);
});
}
/**
* Updates the reaction document with the specified ID with the provided array of user IDs.
* @param reactionId The ID of the reaction document to update.
@ -171,6 +186,24 @@ export class ChatService implements OnDestroy {
}
}
uploadFile(file: File) {
const storage = getStorage();
const storageRef = ref(storage, 'chatFiles/' + file.name);
uploadBytes(storageRef, file)
.then((snapshot) => {
getDownloadURL(storageRef)
.then((url) => {
this.fileSrc = url;
})
.catch((error) =>
console.error('Error retrieving the download URL:', error)
);
})
.catch((error) => {
console.error('Upload error:', error);
});
}
/**
* Unsubscribes from all Firestore subscriptions when the service is destroyed.
*/

View file

@ -1,115 +0,0 @@
import { Injectable } from '@angular/core';
import {
getDownloadURL,
getStorage,
listAll,
ref,
uploadBytes,
} from '@angular/fire/storage';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DownloadFilesService {
uploadFiles: File[] = [];
downloadedFiles: BehaviorSubject<{ id: string; files: string[] }[]> =
new BehaviorSubject<{ id: string; files: string[] }[]>([]);
fileNames: any[] = [];
constructor() {
this.listAllFiles();
}
async checkChatHasFiles(chatId: string): Promise<string | undefined> {
try {
const storage = getStorage();
const listRef = ref(storage, `chatFiles/${chatId}`);
const result = await listAll(listRef);
if (result.items.length > 0) {
return result.items[0].fullPath;
} else {
return undefined;
}
} catch (error) {
console.error('Error listing files:', error);
return undefined;
}
}
/**
* Uploads all files and updates the list.
* @param {string} docID - The documentId under which the files are to be saved.
*/
uploadAllFiles(docID: string) {
const storage = getStorage();
for (const file of this.uploadFiles) {
const storageRef = ref(storage, `chatFiles/${docID}/${file.name}`);
uploadBytes(storageRef, file).then((snapshot) => {
this.listAllFiles();
});
}
}
/**
* Lists all files in 'chatFiles' and updates the downloaded files.
*/
listAllFiles() {
const storage = getStorage();
const listRef2 = ref(storage, 'chatFiles');
listAll(listRef2)
.then(async (res) => {
const downloadedFilesData: { id: string; files: string[] }[] = [];
for (const folderRef of res.prefixes) {
const folderID = folderRef.name;
const folderFiles = [];
const folderRes = await listAll(folderRef);
for (const fileRef of folderRes.items) {
const url = await getDownloadURL(fileRef);
folderFiles.push(url);
}
downloadedFilesData.push({ id: folderID, files: folderFiles });
}
// Emit the updated value
this.downloadedFiles.next(downloadedFilesData);
})
.catch((error) => {
console.error('Error when retrieving the files:', error);
});
}
checkFiles(chatId: string) {
const storage = getStorage();
const listRef = ref(storage, `chatFiles/${chatId}`);
return listAll(listRef)
.then((result) => {
if (result.items.length > 0) {
return result.items[0].fullPath;
}
return;
})
.catch((error) => {
console.error('Error listing files:', error);
return false;
});
}
async downloadFiles(path: string): Promise<string | null> {
try {
const storage = getStorage();
const forestRef = ref(storage, path);
const downloadUrl = await getDownloadURL(forestRef);
return downloadUrl;
} catch (error) {
console.error('Error downloading file:', error);
return null;
}
}
}

View file

@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
import {
getDownloadURL,
getStorage,
ref,
uploadBytes,
} from '@angular/fire/storage';
import { ChatService } from './chat.service';
@Injectable({
providedIn: 'root',
})
export class DownloadFilesService {
uploadFiles: File[] = [];
constructor(private chatService: ChatService) {}
/**
* Uploads all files and updates the list.
* @param {string} docID - The documentId under which the files are to be saved.
*/
uploadAllFiles(docID: string) {
const storage = getStorage();
for (const file of this.uploadFiles) {
const storageRef = ref(storage, `chatFiles/${docID}/${file.name}`);
uploadBytes(storageRef, file)
.then((snapshot) => {
getDownloadURL(storageRef)
.then((url) => {
this.chatService.updateChatFile(docID, url);
})
.catch((error) =>
console.error('Error retrieving the download URL:', error)
);
})
.catch((error) => {
console.error('Upload error:', error);
});
}
}
}