From a0a6fdaf55d1842cc3128ada1f055ee1a0d87996 Mon Sep 17 00:00:00 2001 From: chatenium Date: Wed, 15 Apr 2026 17:35:55 +0200 Subject: [PATCH] 3.0 Beta 7 --- README.md | 4 +- package-lock.json | 8 +- package.json | 2 +- public/i18n/en.json | 12 +- src/app/chat/chat.html | 1 + src/app/chat/dm/dm.html | 2 +- src/app/chat/dm/dm.ts | 70 +++++++++-- .../elements/message-box/message-box.html | 4 +- .../elements/messages/messages-viewmodel.ts | 6 + src/app/chat/elements/messages/messages.html | 45 +++++-- src/app/chat/elements/messages/messages.scss | 4 +- src/app/chat/elements/messages/messages.ts | 4 +- src/app/chat/network/channel/text/text.html | 2 +- src/app/chat/network/channel/text/text.ts | 78 ++++++++++-- src/app/homepage/homepage.html | 119 ++++-------------- src/app/homepage/homepage.scss | 29 +++++ src/app/homepage/homepage.ts | 9 +- src/app/service-manager.ts | 3 + src/environments/environment.development.ts | 2 +- src/environments/environment.ts | 2 +- 20 files changed, 261 insertions(+), 145 deletions(-) create mode 100644 src/app/chat/elements/messages/messages-viewmodel.ts diff --git a/README.md b/README.md index 2bcef04..251edb8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# Chatenium On Web -A modern web application for Chatenium compatible with a wide range of devices. +# Chatenium Nexum +The next generation Web application for Chatenium, built on modern standards powered by Chatenium SDK (TypeScript). diff --git a/package-lock.json b/package-lock.json index fe274ad..6b542bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@angular/platform-browser": "^21.2.0", "@angular/router": "^21.2.0", "@angular/service-worker": "^21.2.0", - "@chatenium/chatenium-sdk": "^1.1.10", + "@chatenium/chatenium-sdk": "^1.1.11", "@fortawesome/angular-fontawesome": "^4.0.0", "@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", @@ -1011,9 +1011,9 @@ } }, "node_modules/@chatenium/chatenium-sdk": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.1.10.tgz", - "integrity": "sha512-FRVKyOzkKQ5wWFL/m3G731VXhvqo3IHpKFcseWfpX5TxBq6Kh9GxpjN8/JQgQ5X+KDES1Nrm4FqOHkVw5CVHyA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@chatenium/chatenium-sdk/-/chatenium-sdk-1.1.11.tgz", + "integrity": "sha512-iwYHyED1AnGcWtyeVo+R1JfxVauuIC5FCX8Rk6RwF+ls/oUIg1aExFgvif2wc0qUyT9mla8ztBt+wBB/cTy4hA==", "dependencies": { "@faker-js/faker": "^10.4.0", "axios": "^1.14.0", diff --git a/package.json b/package.json index d6b4df0..c71fb6c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@angular/platform-browser": "^21.2.0", "@angular/router": "^21.2.0", "@angular/service-worker": "^21.2.0", - "@chatenium/chatenium-sdk": "^1.1.10", + "@chatenium/chatenium-sdk": "^1.1.11", "@fortawesome/angular-fontawesome": "^4.0.0", "@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", diff --git a/public/i18n/en.json b/public/i18n/en.json index a7bab73..e33d5c0 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -1,5 +1,5 @@ { - "version": "3.0 Beta 6 (April 14, 2026)", + "version": "Chatenium Nexum 3.0 Beta 7 (April 15, 2026)", "ok": "Ok", "back": "Back", "aChatProgram": "A messaging platform that you can trust.", @@ -10,13 +10,14 @@ "whatIsChtn": "Chatenium is a chat platform aiming to provide a secure, well integrated fast chatting experience across any devices. You can create a new account for free and start chatting and broadcasting messages.", "updating": "Updating...", "home": { + "soon": "Coming soon...", "chtn": "Chatenium ", "chtnIs": "Chatenium is ", "help": "Help", "blog": "Blog", "apiSpecs": "API specifications", - "adaptsToYou": "adapts to you", - "adaptsToYouDesc": "We actively work on bringing Chatenium to every device, but not the fast way, the good way by developing a native application for each platform.", + "adaptsTo": "Chatenium adapts to ", + "adaptsToYouDesc": "Choose your platform:", "chtnOnWeb": "Chatenium On Web", "chtnOnWebDesc": "Built for maximum compatibility. The Web will work on every device you have.", "chtnOnAndroid": "Chatenium On Androidâ„¢", @@ -105,8 +106,9 @@ "changeLogDialog": { "label": "Chatenium has been updated", "changeLog": { - "1": "UI issue fixes in the message box", - "2": "Added caching to improve performance" + "1": "Added progress bar to files when uploading attachments", + "2": "Bug fixes related to sending messages", + "3": "Fixed scrolling issues when switching chats. Also now the scroll position is now saved" } }, "chatnav": { diff --git a/src/app/chat/chat.html b/src/app/chat/chat.html index a068b51..9406d90 100644 --- a/src/app/chat/chat.html +++ b/src/app/chat/chat.html @@ -4,6 +4,7 @@
- + {{ "chat.elements.messageBox.placeholder"|translate }}
-
diff --git a/src/app/chat/elements/messages/messages-viewmodel.ts b/src/app/chat/elements/messages/messages-viewmodel.ts new file mode 100644 index 0000000..26e04dd --- /dev/null +++ b/src/app/chat/elements/messages/messages-viewmodel.ts @@ -0,0 +1,6 @@ +import {signal} from '@angular/core'; + +export class MessagesViewModel { + // Saves scrolling state. First value initialized when scrolling to bottom on the message load + scrollBarStatus = signal(-1) +} diff --git a/src/app/chat/elements/messages/messages.html b/src/app/chat/elements/messages/messages.html index 31c5867..1302599 100644 --- a/src/app/chat/elements/messages/messages.html +++ b/src/app/chat/elements/messages/messages.html @@ -17,24 +17,47 @@ {{ message.message }} @for (file of filterExpressedMedia(message.files); track file) { - @if (file.type == "image") { - - } @else if (file.type == "video") { +
@if (file.extraMetaData && Object.keys(file.extraMetaData).length > 0) { - - } @else { - + @if (file.extraMetaData['progressShown']) { + + } } - } + @if (file.type == "image") { + + } @else if (file.type == "video") { + @if (file.extraMetaData && Object.keys(file.extraMetaData).length > 0) { + + } @else { + + } + } +
}
@for (file of filterNonExpressedMedia(message.files); track file) { -
- +
+ @if (file.extraMetaData && Object.keys(file.extraMetaData).length > 0) { + @if (file.extraMetaData['progressShown']) { + + } @else { + + } + } @else { + + } {{ file.fileName }}
} diff --git a/src/app/chat/elements/messages/messages.scss b/src/app/chat/elements/messages/messages.scss index ba4111b..92109c1 100644 --- a/src/app/chat/elements/messages/messages.scss +++ b/src/app/chat/elements/messages/messages.scss @@ -31,7 +31,7 @@ } .bubble { - border-radius: 25px 10px 10px 10px !important; + border-radius: 10px 25px 10px 10px !important; } } @@ -43,7 +43,7 @@ &.chained_end { .bubble { - border-radius: 10px 10px 10px 25px !important; + border-radius: 10px 10px 25px 10px !important; } } diff --git a/src/app/chat/elements/messages/messages.ts b/src/app/chat/elements/messages/messages.ts index c93e55d..104a663 100644 --- a/src/app/chat/elements/messages/messages.ts +++ b/src/app/chat/elements/messages/messages.ts @@ -18,6 +18,7 @@ import {TranslatePipe} from '@ngx-translate/core'; import {MessageBoxViewModel} from '../message-box/message-box-viewmodel'; import {FileDataWithPreview} from '../message-box/message-box'; import {Attachment} from '@chatenium/chatenium-sdk/domain/common.schema'; +import {TuiProgressCircle} from '@taiga-ui/kit'; @Component({ selector: 'messages', @@ -32,7 +33,8 @@ import {Attachment} from '@chatenium/chatenium-sdk/domain/common.schema'; TranslatePipe, TuiDataListComponent, TuiGroup, - TuiIcon + TuiIcon, + TuiProgressCircle ], templateUrl: './messages.html', styleUrl: './messages.scss', diff --git a/src/app/chat/network/channel/text/text.html b/src/app/chat/network/channel/text/text.html index c14871f..451bf13 100644 --- a/src/app/chat/network/channel/text/text.html +++ b/src/app/chat/network/channel/text/text.html @@ -25,7 +25,7 @@
- diff --git a/src/app/chat/network/channel/text/text.ts b/src/app/chat/network/channel/text/text.ts index 32b88f0..0d5e282 100644 --- a/src/app/chat/network/channel/text/text.ts +++ b/src/app/chat/network/channel/text/text.ts @@ -12,6 +12,8 @@ import {Message} from '@chatenium/chatenium-sdk/domain/textChannelService.schema import {Messages} from '../../../elements/messages/messages'; import {Navbar} from '../../../elements/navbar/navbar'; import {Oimg} from '../../../elements/oimg/oimg'; +import {MessagesViewModel} from '../../../elements/messages/messages-viewmodel'; +import {v4 as uuidv4} from 'uuid'; @Component({ selector: 'app-text', @@ -65,15 +67,16 @@ export class Text { } } - this.store.messageBox.editingMessage.set(null) - this.store.messageBox.message.set("") return } let attachments: Attachment[] = [] files?.forEach(file => { - const extraMetaData: Record = {} + const extraMetaData: Record = {} extraMetaData["thumbnailMetaData"] = file.videoThumbnail ?? "" + extraMetaData["progressShown"] = true + extraMetaData["totalChunks"] = 0 + extraMetaData["uploadedChunks"] = 0 attachments.push({ fileName: file.name, @@ -87,6 +90,7 @@ export class Text { }) }) + const tempMsgId = uuidv4() this.store.messages.update(value => [...value, { author: { userid: session.userData.userid, @@ -94,7 +98,7 @@ export class Text { username: session.userData.username, displayName: session.userData.displayName }, - msgid: "", + msgid: tempMsgId, message: message, sent_at: { T: 0, @@ -104,7 +108,7 @@ export class Text { channelId: "", networkId: "", categoryId: "", - files: [], + files: attachments, seen: false, replyTo: "", replyToId: "", @@ -114,11 +118,12 @@ export class Text { this.scrollToBottom("smooth") - await this.store.service.sendMessage("", message, null, null, files, { + const respMessage = await this.store.service.sendMessage(tempMsgId, message, null, null, files, { fileProgressUpdate: (tempMsgId, fileId, allChunks, chunksDone) => { this.uploadProgressUpdate(tempMsgId, fileId, allChunks, chunksDone) } }) + this.updateTempMessage(tempMsgId, respMessage) } } @@ -138,19 +143,69 @@ export class Text { scrollToBottom(anim: 'instant' | 'smooth'): void { setTimeout(() => { + if (!this.store) { + return + } const scrollContainer = document.querySelector("#scrollContainer") scrollContainer.scroll({ - top: scrollContainer.scrollHeight, + top: this.store.messagesVm.scrollBarStatus() == -1 ? scrollContainer.scrollHeight : this.store.messagesVm.scrollBarStatus(), left: 0, behavior: anim }); + + if (this.store.messagesVm.scrollBarStatus() == -1) { + this.store.messagesVm.scrollBarStatus.set(scrollContainer.scrollHeight) + } }, 0) } - uploadProgressUpdate(tempMsgId: string, fileId: string, allChunks: number, chunksDone: number) { - console.log(fileId, allChunks, chunksDone) + handleMessagesScroll(e: any) { + if (!this.store) return + this.store.messagesVm.scrollBarStatus.set(e.target.scrollTop) } + uploadProgressUpdate(tempMsgId: string, fileId: string, allChunks: number, chunksDone: number) { + if (!this.store) return + this.store.messages.update(messages => + messages.map(m => { + if (m.msgid !== tempMsgId) return m; + + return { + ...m, + files: m.files.map(f => { + if (f.fileId !== fileId) return f; + return { + ...f, + extraMetaData: { + ...f.extraMetaData, + totalChunks: allChunks, + uploadedChunks: chunksDone + } + }; + }) + }; + }) + ); + } + + updateTempMessage(tempMsgId: string, message: Message) { + if (!this.store) return + this.store.messages.update(messages => + messages.map(m => { + if (m.msgid !== tempMsgId) return m; + + return { + ...m, + msgid: message.msgid, + sent_at: message.sent_at, + files: m.files.map(f => { + f.extraMetaData["progressShown"] = false + return f + }) + }; + }) + ); + } // The chatid parameter ensures isolation onWsListen(action: string, message: string, networkId: string, channelId: string) { const data = JSON.parse(message); @@ -205,6 +260,7 @@ export class Text { categoryData: signal(categoryData), channelData: signal(channelData), messages: signal([]), + messagesVm: new MessagesViewModel(), messageBox: new MessageBoxViewModel((msg, files) => this.sendMessage(msg, files)), wsListener: (action, data) => this.onWsListen(action, data, networkId, categoryId), } as TextChannelStorage; @@ -225,13 +281,17 @@ export class Text { try { const messagesCache = await currentStore.service.getQuick(); currentStore.messages.set(messagesCache); + this.scrollToBottom("instant") } catch (e) { console.warn(`Cache load failed: ${e}. Skipping cache load...`) } const messages = await currentStore.service.get(); currentStore.messages.set(messages); + this.scrollToBottom("instant") await currentStore.service.joinWebSocketRoom(); + } else { + this.scrollToBottom("instant") } }); } diff --git a/src/app/homepage/homepage.html b/src/app/homepage/homepage.html index 800d15e..e3e1d6d 100644 --- a/src/app/homepage/homepage.html +++ b/src/app/homepage/homepage.html @@ -70,6 +70,11 @@ {{'home.enterChtnOnWeb'|translate}} + + @@ -82,71 +87,6 @@
-
-
-

{{ 'home.chtn'|translate }} - {{ 'home.adaptsToYou'|translate }}

-

{{ 'home.adaptsToYouDesc'|translate }}

- -
-
- - -

{{ 'home.chtnOnWeb'|translate }}

-

{{ 'home.chtnOnWebDesc'|translate }}

-
- -
- - -

{{ 'home.chtnOnAndroid'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnOnAndroidDesc'|translate }}

-
- -
- - -

{{ 'home.chtnOnApple'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnOnAppleDesc'|translate }}

-
- -
- - -

{{ 'home.chtnOnWindows'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnOnWindowsDesc'|translate }}

-
- -
- - -

{{ 'home.chtnOnLinux'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnOnLinuxDesc'|translate }}

-
- -
- - -

{{ 'home.chtnEcho'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnEchoDesc'|translate }}

-
- -
- - -

{{ 'home.chtnReson'|translate }}

-
{{'home.openBeta'|translate}}
-

{{ 'home.chtnResonDesc'|translate }}

-
-
-
-
-

{{ 'home.chtnIs'|translate }} @@ -192,48 +132,35 @@

-
+
-

{{ 'home.weAreExcitedFor'|translate }} +

{{ 'home.adaptsTo'|translate }} {{ 'home.you'|translate }}

-

{{ 'home.weAreExcitedForYouDesc'|translate }}

+

{{ 'home.adaptsToYouDesc'|translate }}

-
- - -

{{ 'home.enterChtnOnWeb'|translate }}

-

{{ 'home.enterChtnOnWebDesc'|translate }}

+
+ +

Linux

+
{{'home.soon'|translate}}
-
- - -

{{ 'home.downloadChtnOnAndroid'|translate }}

-
{{'home.openBeta'|translate}}
-

{{'home.openBetaDesc'|translate}}

- - +
+ +

Google

+
{{'home.soon'|translate}}
-
- - -

{{ 'home.downloadChtnOnApple'|translate }}

-
{{'home.openBeta'|translate}}
-

{{'home.openBetaDesc'|translate}}

- - +
+ +

Apple

+
{{'home.soon'|translate}}
-
+
- -

{{ 'home.downloadOnWindows'|translate }}

-
{{'home.openBeta'|translate}}
-

{{'home.openBetaDesc'|translate}}

- - +

Microsoft

+
{{'home.soon'|translate}}
diff --git a/src/app/homepage/homepage.scss b/src/app/homepage/homepage.scss index 6de78f6..af82ddb 100644 --- a/src/app/homepage/homepage.scss +++ b/src/app/homepage/homepage.scss @@ -117,6 +117,35 @@ main { font-size: 20px; } } + + #platformList { + .cardList { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + + .card { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + gap: 10px; + aspect-ratio: 1/1; + background: var(--tui-background-base); + border-radius: 1.5rem; + cursor: pointer; + + &.disabled { + pointer-events: none; + opacity: 0.5; + } + + fa-icon { + display: flex; + justify-content: center; + align-items: center; + } + } + } + } } .logo { diff --git a/src/app/homepage/homepage.ts b/src/app/homepage/homepage.ts index d73f01f..4c89fe1 100644 --- a/src/app/homepage/homepage.ts +++ b/src/app/homepage/homepage.ts @@ -8,7 +8,7 @@ import {FaIconComponent} from '@fortawesome/angular-fontawesome'; import { faAndroid, faApple, - faAppStoreIos, + faAppStoreIos, faGitAlt, faGitee, faGoogle, faGooglePlay, faLinux, faMicrosoft, @@ -97,6 +97,10 @@ export class Homepage { window.open('https://help.chatenium.hu/s/169154db-df3e-44cb-980d-2db1915ecdf8', '_blank') } + openGit() { + window.open('https://git.chatenium.hu', '_blank') + } + openMsStore() { window.open('https://apps.microsoft.com/detail/9p1xq5vb62b0?ocid=webpdpshare', '_blank') } @@ -150,4 +154,7 @@ export class Homepage { protected readonly faGooglePlay = faGooglePlay; protected readonly faAppStoreIos = faAppStoreIos; protected readonly faMicrosoft = faMicrosoft; + protected readonly faGoogle = faGoogle; + protected readonly faGitee = faGitee; + protected readonly faGitAlt = faGitAlt; } diff --git a/src/app/service-manager.ts b/src/app/service-manager.ts index 8956f65..3c7ab2d 100644 --- a/src/app/service-manager.ts +++ b/src/app/service-manager.ts @@ -16,6 +16,7 @@ import {Message as NetworkMessage} from '@chatenium/chatenium-sdk/domain/textCha import {PictureService} from '@chatenium/chatenium-sdk/services/pictureService'; import {Album} from '@chatenium/chatenium-sdk/domain/pictureService.schema'; import {PublicUserData} from '@chatenium/chatenium-sdk/domain/common.schema'; +import {MessagesViewModel} from './chat/elements/messages/messages-viewmodel'; @Injectable({ providedIn: 'root', @@ -52,6 +53,7 @@ export enum LoadStatus { export interface DmStorage { service: DMService messages: WritableSignal + messagesVm: MessagesViewModel chatData: WritableSignal messageBox: MessageBoxViewModel wsListener: (action: string, message: string) => void @@ -73,6 +75,7 @@ export interface NetworkStorage { export interface TextChannelStorage { service: TextChannelServiceService messages: WritableSignal + messagesVm: MessagesViewModel channelData: WritableSignal categoryData: WritableSignal messageBox: MessageBoxViewModel diff --git a/src/environments/environment.development.ts b/src/environments/environment.development.ts index 3f31484..85f0df3 100644 --- a/src/environments/environment.development.ts +++ b/src/environments/environment.development.ts @@ -1,5 +1,5 @@ export const environment = { - version: "3.0-beta6", + version: "3.0-beta7", api_url: "http://localhost:3000", cdn_url: "http://localhost:4000", ws_url: "ws://localhost:3000", diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 33e5ffd..d97a5ac 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,5 +1,5 @@ export const environment = { - version: "3.0-beta6", + version: "3.0-beta7", api_url: "https://api.chatenium.hu", cdn_url: "https://cdn.chatenium.hu", ws_url: "wss://api.chatenium.hu",