Added file uploading + drag'n'drop
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -15,7 +15,7 @@
|
|||||||
"@angular/forms": "^21.2.0",
|
"@angular/forms": "^21.2.0",
|
||||||
"@angular/platform-browser": "^21.2.0",
|
"@angular/platform-browser": "^21.2.0",
|
||||||
"@angular/router": "^21.2.0",
|
"@angular/router": "^21.2.0",
|
||||||
"@chatenium/chatenium-sdk": "^1.0.10",
|
"@chatenium/chatenium-sdk": "^1.0.11",
|
||||||
"@ngx-translate/core": "^17.0.0",
|
"@ngx-translate/core": "^17.0.0",
|
||||||
"@ngx-translate/http-loader": "^17.0.0",
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
"@taiga-ui/addon-charts": "^5.1.0",
|
"@taiga-ui/addon-charts": "^5.1.0",
|
||||||
@@ -988,9 +988,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@chatenium/chatenium-sdk": {
|
"node_modules/@chatenium/chatenium-sdk": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.0.11.tgz",
|
||||||
"integrity": "sha512-AhWtM4bD3p1nXW/tC/eiBlPGesk/vjwjf1CPuScYaD2OwmXLGZXNZPXe3g6T5dRAA1Zyo18QkWEJXglA+6VZSQ==",
|
"integrity": "sha512-2vkN+W541bMEdWTStrXorsEmbQ9mva6drKOU11yFdVMzpPEsMJr9bvk5Lwc5COpOgNTIbnFSAkzPg+0USFruVQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^10.4.0",
|
"@faker-js/faker": "^10.4.0",
|
||||||
"axios": "^1.14.0",
|
"axios": "^1.14.0",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@angular/forms": "^21.2.0",
|
"@angular/forms": "^21.2.0",
|
||||||
"@angular/platform-browser": "^21.2.0",
|
"@angular/platform-browser": "^21.2.0",
|
||||||
"@angular/router": "^21.2.0",
|
"@angular/router": "^21.2.0",
|
||||||
"@chatenium/chatenium-sdk": "^1.0.10",
|
"@chatenium/chatenium-sdk": "^1.0.11",
|
||||||
"@ngx-translate/core": "^17.0.0",
|
"@ngx-translate/core": "^17.0.0",
|
||||||
"@ngx-translate/http-loader": "^17.0.0",
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
"@taiga-ui/addon-charts": "^5.1.0",
|
"@taiga-ui/addon-charts": "^5.1.0",
|
||||||
|
|||||||
@@ -42,12 +42,6 @@ export class Dm implements OnInit {
|
|||||||
async sendMessage(message: string, files: FileDataWithPreview[] | null) {
|
async sendMessage(message: string, files: FileDataWithPreview[] | null) {
|
||||||
const session = this.serviceManager.currentSession();
|
const session = this.serviceManager.currentSession();
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
await this.store.service.sendMessage(message, null, null, files, <FileUploadProgressListener>{
|
|
||||||
fileProgressUpdate: (fileId, allChunks, chunksDone) => {
|
|
||||||
this.uploadProgressUpdate(fileId, allChunks, chunksDone)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let attachments: Attachment[] = []
|
let attachments: Attachment[] = []
|
||||||
files?.forEach(file => {
|
files?.forEach(file => {
|
||||||
attachments.push({
|
attachments.push({
|
||||||
@@ -75,10 +69,16 @@ export class Dm implements OnInit {
|
|||||||
replyToId: "",
|
replyToId: "",
|
||||||
forwardedFromName: ""
|
forwardedFromName: ""
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
await this.store.service.sendMessage("", message, null, null, files, <FileUploadProgressListener>{
|
||||||
|
fileProgressUpdate: (tempMsgId, fileId, allChunks, chunksDone) => {
|
||||||
|
this.uploadProgressUpdate(tempMsgId, fileId, allChunks, chunksDone)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadProgressUpdate(fileId: string, allChunks: number, chunksDone: number) {
|
uploadProgressUpdate(tempMsgId: string, fileId: string, allChunks: number, chunksDone: number) {
|
||||||
console.log(fileId, allChunks, chunksDone)
|
console.log(fileId, allChunks, chunksDone)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,5 @@ export class MessageBoxViewModel {
|
|||||||
|
|
||||||
message = signal<string>("")
|
message = signal<string>("")
|
||||||
files = signal<FileDataWithPreview[]>([])
|
files = signal<FileDataWithPreview[]>([])
|
||||||
|
dialogOpen = signal<boolean>(false)
|
||||||
get dialogOpen() {
|
|
||||||
return this.files().length != 0
|
|
||||||
}
|
|
||||||
set dialogOpen(value: boolean) {
|
|
||||||
this.files.set([])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div id="dragOverlay" tuiGroup orientation="vertical" [class.show]="isDraggingOverWindow">
|
<div id="dragOverlay" tuiGroup orientation="vertical" [class.show]="isDraggingOverWindow">
|
||||||
<div class="method">
|
<div class="method" (drop)="onDrop($event)" (dragover)="onDragOver($event)">
|
||||||
<div class="icon-holder">
|
<div class="icon-holder">
|
||||||
<tui-icon icon="@tui.file-up"/>
|
<tui-icon icon="@tui.file-up"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
></textarea>
|
></textarea>
|
||||||
</tui-textfield>
|
</tui-textfield>
|
||||||
|
|
||||||
<button tuiButton iconStart="@tui.send" (click)="sendMessageWithCaption(caption)"></button>
|
<button tuiButton iconStart="@tui.send" (click)="sendMessageWithCaption()"></button>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Component, HostListener, inject, input} from '@angular/core';
|
import {ChangeDetectorRef, Component, HostListener, inject, input} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
TuiAppearance,
|
TuiAppearance,
|
||||||
TuiButton,
|
TuiButton,
|
||||||
@@ -40,6 +40,8 @@ import {TuiTextarea, TuiTextareaComponent} from '@taiga-ui/kit';
|
|||||||
export class MessageBox {
|
export class MessageBox {
|
||||||
viewModel = input.required<MessageBoxViewModel>()
|
viewModel = input.required<MessageBoxViewModel>()
|
||||||
|
|
||||||
|
cdr = inject(ChangeDetectorRef)
|
||||||
|
|
||||||
textareaHeight = 25
|
textareaHeight = 25
|
||||||
messageBoxRadius = 200
|
messageBoxRadius = 200
|
||||||
|
|
||||||
@@ -68,6 +70,22 @@ export class MessageBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDragOver(event: DragEvent) {
|
||||||
|
// This is the "magic" line that enables the drop event to fire
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop(event: DragEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const files = event.dataTransfer?.files;
|
||||||
|
if (files) this.processFiles(files)
|
||||||
|
this.isDraggingOverWindow = false
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
onTextAreaInput(e: HTMLTextAreaElement) {
|
onTextAreaInput(e: HTMLTextAreaElement) {
|
||||||
const calculatedHeight = e.value.split(/\r?\n/).length * 25
|
const calculatedHeight = e.value.split(/\r?\n/).length * 25
|
||||||
const calculatedRadius = (200 - this.textareaHeight)
|
const calculatedRadius = (200 - this.textareaHeight)
|
||||||
@@ -79,8 +97,10 @@ export class MessageBox {
|
|||||||
this.processFiles(event.target.files)
|
this.processFiles(event.target.files)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessageWithCaption(e: TuiTextareaComponent) {
|
sendMessageWithCaption() {
|
||||||
this.viewModel().onMessageSend((e.content() as string), this.viewModel().files())
|
this.viewModel().onMessageSend(this.viewModel().message(), this.viewModel().files())
|
||||||
|
this.viewModel().files.set([])
|
||||||
|
this.viewModel().dialogOpen.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async processFiles(fileList: FileList) {
|
async processFiles(fileList: FileList) {
|
||||||
@@ -116,8 +136,8 @@ export class MessageBox {
|
|||||||
height: height,
|
height: height,
|
||||||
width: width,
|
width: width,
|
||||||
})
|
})
|
||||||
console.log(this.viewModel().files())
|
|
||||||
}
|
}
|
||||||
|
this.viewModel().dialogOpen.set(true)
|
||||||
|
|
||||||
function makePicturePreview(file: File): Promise<{ preview: string, height: number, width: number }> {
|
function makePicturePreview(file: File): Promise<{ preview: string, height: number, width: number }> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -143,6 +163,8 @@ export class MessageBox {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly console = console;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,11 +12,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="bubble">
|
<div class="bubble">
|
||||||
<span class="message-text">{{message.message}}</span>
|
<span class="message-text">{{message.message}}</span>
|
||||||
|
<masonry style="max-height: 300px">
|
||||||
@for (file of message.files; track file) {
|
@for (file of message.files; track file) {
|
||||||
@if (file.type == "image") {
|
@if (file.type == "image") {
|
||||||
<img [src]="file.path"/>
|
<img [src]="file.path" style="width: 100%; height: 100%; max-height: 300px; object-fit: cover; border-radius: 25px"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
</masonry>
|
||||||
</div>
|
</div>
|
||||||
<div class="below"></div>
|
<div class="below"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -57,8 +57,9 @@
|
|||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 5px;
|
justify-content: center;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
.message-text {
|
.message-text {
|
||||||
white-space: none;
|
white-space: none;
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import {Message} from '@chatenium/chatenium-sdk/domain/dmService.schema';
|
|||||||
import {Message as NetworkMessage} from '@chatenium/chatenium-sdk/domain/textChannelService.schema'
|
import {Message as NetworkMessage} from '@chatenium/chatenium-sdk/domain/textChannelService.schema'
|
||||||
import {ServiceManager} from '../../../service-manager';
|
import {ServiceManager} from '../../../service-manager';
|
||||||
import {DatePipe} from '@angular/common';
|
import {DatePipe} from '@angular/common';
|
||||||
|
import {Masonry} from '../masonry/masonry';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'messages',
|
selector: 'messages',
|
||||||
imports: [
|
imports: [
|
||||||
DatePipe
|
DatePipe,
|
||||||
|
Masonry
|
||||||
],
|
],
|
||||||
templateUrl: './messages.html',
|
templateUrl: './messages.html',
|
||||||
styleUrl: './messages.scss',
|
styleUrl: './messages.scss',
|
||||||
|
|||||||
Reference in New Issue
Block a user