Skip to content

Commit

Permalink
Merge pull request #884 from AiursoftWeb/dev
Browse files Browse the repository at this point in the history
Release 4.1.1
  • Loading branch information
Anduin2017 authored May 15, 2020
2 parents 055c9f0 + 8564099 commit 4e162ad
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 63 deletions.
1 change: 1 addition & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"src/assets",
"src/manifest.json",
"src/favicon.ico",
"src/favicon_notify.ico",
"src/web.config",
"src/robots.txt",
"src/sw.js",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kahla",
"version": "4.1.0",
"version": "4.1.1",
"description": "Kahla is a cross-platform business messaging app.",
"author": "Aiursoft <service@aiursoft.com> (https://www.aiursoft.com/)",
"build": {
Expand Down
2 changes: 1 addition & 1 deletion src/app/Controllers/share.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class ShareComponent implements OnInit, DoCheck {
if (this.fileRef) {
// get file path
const filePath = this.relativePath ? this.fileRef.filePath :
this.fileRef.filePath.match(new RegExp(`.+\/conversation-${this.srcConversation}\/(.+)`))[1];
this.fileRef.filePath.match(new RegExp(`.+\/conversation-${this.srcConversation}\/(.+)`))?.[1];
if (!filePath) {
resolve();
Swal.fire('Failed.', 'Sorry, but you can\'t share this file.', 'error');
Expand Down
38 changes: 24 additions & 14 deletions src/app/Controllers/talking.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ export class TalkingComponent implements OnInit, OnDestroy {
if (e.key === 'Enter' && !this.showUserList) {
e.preventDefault();
if ((e.altKey || e.ctrlKey || e.shiftKey) === this.cacheService.cachedData.me.enableEnterToSendMessage) {
const input = <HTMLTextAreaElement>document.getElementById('chatInput');
this.content = `${this.content.slice(0, input.selectionStart)}\n${this.content.slice(input.selectionStart)}`;
this.updateInputHeight();
this.insertToSelection('\n');
this.oldContent = ''; // prevent send message on keyup
} else {
this.oldContent = this.content;
Expand Down Expand Up @@ -297,11 +295,7 @@ export class TalkingComponent implements OnInit, OnDestroy {
},
next: p => {
this.messageService.localMessages.splice(this.messageService.localMessages.indexOf(tempMessage), 1);
this.messageService.rawMessages.push(p.value);
this.messageService.localMessages.push(this.messageService.modifyMessage(Object.assign({}, p.value)));
this.messageService.reorderLocalMessages();
this.messageService.updateAtLink();
this.messageService.saveMessage();
this.messageService.insertMessage(p.value);
}
});
this.content = '';
Expand Down Expand Up @@ -344,10 +338,8 @@ export class TalkingComponent implements OnInit, OnDestroy {
public togglePanel(): void {
this.showPanel = !this.showPanel;
if (this.showPanel) {
document.querySelector('.message-list').classList.add('active-list');
window.scroll(0, window.scrollY + 105);
} else {
document.querySelector('.message-list').classList.remove('active-list');
if (this.messageService.belowWindowPercent <= 0.2) {
this.uploadService.scrollBottom(false);
} else {
Expand All @@ -373,7 +365,11 @@ export class TalkingComponent implements OnInit, OnDestroy {
if (fileType !== FileType.File) {
files = this.probeService.renameFile(files, fileType === FileType.Image ? 'img_' : 'video_');
}
this.uploadService.upload(files, this.messageService.conversation.id, this.messageService.conversation.aesKey, fileType);
this.uploadService.upload(files, this.messageService.conversation.id, this.messageService.conversation.aesKey, fileType)
?.then(t => {
this.messageService.insertMessage(t.value);
setTimeout(() => this.uploadService.scrollBottom(true), 0);
});
}
}

Expand All @@ -393,7 +389,10 @@ export class TalkingComponent implements OnInit, OnDestroy {
}).then((send) => {
if (send.value) {
this.uploadService.upload(blob, this.messageService.conversation.id,
this.messageService.conversation.aesKey, FileType.Image);
this.messageService.conversation.aesKey, FileType.Image)?.then(t => {
this.messageService.insertMessage(t.value);
setTimeout(() => this.uploadService.scrollBottom(true), 0);
});
}
URL.revokeObjectURL(urlString);
});
Expand Down Expand Up @@ -437,7 +436,11 @@ export class TalkingComponent implements OnInit, OnDestroy {
fileType = FileType.Video;
}

this.uploadService.upload(t, this.messageService.conversation.id, this.messageService.conversation.aesKey, fileType);
this.uploadService.upload(t, this.messageService.conversation.id, this.messageService.conversation.aesKey, fileType)
?.then(msg => {
this.messageService.insertMessage(msg.value);
setTimeout(() => this.uploadService.scrollBottom(true), 0);
});
});
this.removeDragData(event);
}
Expand Down Expand Up @@ -495,7 +498,7 @@ export class TalkingComponent implements OnInit, OnDestroy {
showSearch: false
});
this.picker.on('emoji', emoji => {
this.content = this.content ? this.content + emoji : emoji;
this.insertToSelection(emoji);
});
}
this.picker.togglePicker(chatBox);
Expand Down Expand Up @@ -555,6 +558,13 @@ export class TalkingComponent implements OnInit, OnDestroy {
}
}

public insertToSelection(content: string) {
const input = <HTMLTextAreaElement>document.getElementById('chatInput');
this.content = this.content ? `${this.content.slice(0, input.selectionStart)
}${content}${this.content.slice(input.selectionStart)}` : content;
this.updateInputHeight();
}

public getAudio(target: HTMLElement, filePath: string): void {
target.style.display = 'none';
const audioElement = document.createElement('audio');
Expand Down
3 changes: 2 additions & 1 deletion src/app/Models/Timers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export enum Timers {
'5s' = 5,
'30s' = 30,
'1m' = 60,
'10m' = 600,
'1h' = 3600,
'1d' = 3600 * 24,
'1w' = 3600 * 24 * 7,
'1mo' = 3600 * 24 * 30,
'1y' = 3600 * 24 * 365,
'off' = Math.pow(2, 31) - 1
}
15 changes: 14 additions & 1 deletion src/app/Services/CacheService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DevicesApiService } from './DevicesApiService';
import { ConversationApiService } from './ConversationApiService';
import { ProbeService } from './ProbeService';
import { PushSubscriptionSetting } from '../Models/PushSubscriptionSetting';
import { ThemeService } from './ThemeService';

@Injectable()
export class CacheService {
Expand All @@ -19,7 +20,9 @@ export class CacheService {
private devicesApiService: DevicesApiService,
private conversationApiService: ConversationApiService,
private probeService: ProbeService,
) { }
private themeService: ThemeService,
) {
}

public reset() {
this.cachedData = new CacheModel();
Expand Down Expand Up @@ -129,6 +132,15 @@ export class CacheService {
}
});
this.cachedData.devices = response.items;
// should check if current device id has already been invalid
if (localStorage.getItem('setting-pushSubscription')) {
const val = JSON.parse(localStorage.getItem('setting-pushSubscription')) as PushSubscriptionSetting;
if (val.deviceId && !this.cachedData.devices.find(t => t.id === val.deviceId)) {
// invalid id, remove it
val.deviceId = null;
localStorage.setItem('setting-pushSubscription', JSON.stringify(val));
}
}
this.saveCache();
});
}
Expand All @@ -155,6 +167,7 @@ export class CacheService {
public updateTotalUnread(): void {
this.totalUnread = this.cachedData.conversations
.filter(item => !item.muted).map(item => item.unReadAmount).reduce((a, b) => a + b, 0);
this.themeService.NotifyIcon = this.totalUnread;
}

public initCache(): void {
Expand Down
8 changes: 3 additions & 5 deletions src/app/Services/InitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,9 @@ export class InitService {
localStorage.setItem('setting-pushSubscription', JSON.stringify(data));
}
if (!data.enabled && data.deviceId) {
this.devicesApiService.DropDevice(data.deviceId).subscribe(t => {
if (t.code === 0) {
data.deviceId = 0;
localStorage.setItem('setting-pushSubscription', JSON.stringify(data));
}
this.devicesApiService.DropDevice(data.deviceId).subscribe(_t => {
data.deviceId = 0;
localStorage.setItem('setting-pushSubscription', JSON.stringify(data));
});
}
if (data.enabled) {
Expand Down
11 changes: 11 additions & 0 deletions src/app/Services/MessageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,15 @@ export class MessageService {
this.fileAccessToken = encodeURIComponent(t.value);
});
}

public insertMessage(p: Message) {
if (this.rawMessages.find(t => t.id === p.id)) {
return;
}
this.rawMessages.push(p);
this.localMessages.push(this.modifyMessage(Object.assign({}, p)));
this.reorderLocalMessages();
this.updateAtLink();
this.saveMessage();
}
}
13 changes: 13 additions & 0 deletions src/app/Services/ThemeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class ThemeService {
}

public mediaListener: MediaQueryList;
public readonly TITLE = 'Kahla - Aiursoft';

ApplyThemeFromRemote(remoteInfo: KahlaUser) {
if (this.LocalThemeSetting !== remoteInfo.themeId) {
Expand Down Expand Up @@ -132,4 +133,16 @@ export class ThemeService {
localStorage.setItem('setting-theme', theme.toString());
}

public set NotifyIcon(value: number) {
if (value !== 0) {
document.title = `(${value}) ${this.TITLE}`;
document.querySelector('link[rel=icon]')
.setAttribute('href', 'favicon_notify.ico');
} else {
document.title = this.TITLE;
document.querySelector('link[rel=icon]')
.setAttribute('href', 'favicon.ico');
}
}

}
3 changes: 2 additions & 1 deletion src/app/Services/TimerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ export class TimerService {
input: 'select',
inputOptions: {
5: '5 seconds',
30: '30 seconds',
60: '1 minute',
600: '10 minutes',
3600: '1 hour',
[3600 * 24]: '1 day',
[3600 * 24 * 7]: '1 week',
[3600 * 24 * 30]: '1 month',
[3600 * 24 * 365]: '1 year',
[Math.pow(2, 31) - 1]: 'off'
},
inputPlaceholder: 'Select one',
Expand Down
70 changes: 38 additions & 32 deletions src/app/Services/UploadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { FileType } from '../Models/FileType';
import { ProbeService } from './ProbeService';
import { uuid4 } from '../Helpers/Uuid';
import { MessageFileRef } from '../Models/MessageFileRef';
import { AiurValue } from '../Models/AiurValue';
import { Message } from '../Models/Message';

@Injectable({
providedIn: 'root'
Expand All @@ -25,7 +27,7 @@ export class UploadService {
) {
}

public upload(file: File, conversationID: number, aesKey: string, fileType: FileType): void {
public upload(file: File, conversationID: number, aesKey: string, fileType: FileType): Promise<AiurValue<Message>> {
if (!this.validateFileSize(file)) {
Swal.fire('Error', 'File size should larger than or equal to one bit and less then or equal to 2047MB.', 'error');
return;
Expand Down Expand Up @@ -67,30 +69,36 @@ export class UploadService {
});
} else {
const alert = this.fireUploadingAlert(`Uploading your ${fileType === FileType.Image ? 'image' : (fileType === FileType.Video ? 'video' : 'file')}...`);

this.filesApiService.InitFileAccess(conversationID, true).subscribe(response => {
if (response.code === 0) {
const mission = this.filesApiService.UploadFile(formData, response.uploadAddress).subscribe(res => {
if (Number(res)) {
this.updateAlertProgress(Number(res));
} else if (res) {
Swal.close();
this.buildFileRef(res, fileType, file)?.then(t => {
this.encryptThenSend(t, conversationID, aesKey).then(() => {
this.scrollBottom(true);
return new Promise<AiurValue<Message>>((resolve, reject) => {
this.filesApiService.InitFileAccess(conversationID, true).subscribe(response => {
if (response.code === 0) {
const mission = this.filesApiService.UploadFile(formData, response.uploadAddress).subscribe(res => {
if (Number(res)) {
this.updateAlertProgress(Number(res));
} else if (res) {
Swal.close();
this.buildFileRef(res, fileType, file)?.then(t => {
this.encryptThenSend(t, conversationID, aesKey).then((t_) => {
this.scrollBottom(true);
resolve(t_);
});
});
});
}
}, () => {
Swal.close();
Swal.fire('Error', 'Upload failed', 'error');
});
alert.then(result => {
if (result.dismiss) {
mission.unsubscribe();
}
});
}
}
}, () => {
Swal.close();
Swal.fire('Error', 'Upload failed', 'error');
reject();
});
alert.then(result => {
if (result.dismiss) {
mission.unsubscribe();
reject();
}
});
} else {
reject();
}
});
});
}
}
Expand All @@ -113,7 +121,7 @@ export class UploadService {
(<HTMLDivElement>Swal.getContent().querySelector('#progressText')).innerText = `${progress}%`;
}

public encryptThenSend(fileRef: MessageFileRef, conversationID: number, aesKey: string): Promise<void> {
public encryptThenSend(fileRef: MessageFileRef, conversationID: number, aesKey: string): Promise<AiurValue<Message>> {
if (!fileRef) {
return null;
}
Expand All @@ -133,11 +141,11 @@ export class UploadService {
}
}

private sendMessage(message: string, conversationID: number, aesKey: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
private sendMessage(message: string, conversationID: number, aesKey: string): Promise<AiurValue<Message>> {
return new Promise((resolve, reject) => {
this.conversationApiService.SendMessage(conversationID, AES.encrypt(message, aesKey).toString(), uuid4(), [])
.subscribe(() => {
resolve();
.subscribe((t) => {
resolve(t);
}, () => {
Swal.fire('Send Failed.', 'Please check your network connection.', 'error');
reject();
Expand All @@ -155,9 +163,7 @@ export class UploadService {
public scrollBottom(smooth: boolean): void {
if (!this.talkingDestroyed) {
const h = document.documentElement.scrollHeight;
if (document.querySelector('.message-list').scrollHeight < window.innerHeight - 50) {
window.scroll(0, 0);
} else if (smooth) {
if (smooth) {
window.scroll({top: h, behavior: 'smooth'});
} else {
window.scroll(0, h);
Expand Down
7 changes: 1 addition & 6 deletions src/app/Views/talking.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<app-header returnButton="true" shadow="true" #header closeDirectly="true" [processing]="messageService.messageLoading">
</app-header>
<ul id="messageList" class="message-list" (paste)="paste($event)" (drop)="drop($event)"
<ul id="messageList" class="message-list" [class.active-list]="showPanel" (paste)="paste($event)" (drop)="drop($event)"
(dragover)="preventDefault($event)" (click)="hideUserList()">
<button *ngIf="!messageService.loadingMore && !messageService.noMoreMessages" class="load-more" (click)="LoadMore()"
i18n="@@ClickToLoadMore">Click to load more
Expand All @@ -24,11 +24,6 @@
<div class="chart-avatar-wrapper" *ngIf="!message.groupWithPrevious"
routerLink="/user/{{message.senderId}}">
<img src="{{probeService.encodeProbeFileUrl(message.sender.iconFilePath)}}?w=128&square=true">
<div class="small-dot"
style="top: -10px; right: -35px;" *ngIf="message.sender.isOnline !== null"
[class.greendot]="message.sender.isOnline"
[class.graydot]="!message.sender.isOnline">
</div>
</div>
</div>
<div class="message-block">
Expand Down
Binary file added src/favicon_notify.ico
Binary file not shown.
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<meta name="description" content="As a cross-platform business messaging app, Kahla can encrypt communications at any location, on any device. And it is completely open source and free." />
<meta charset="UTF-8">
<meta name="theme-color" content="#2391D3">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="dns-prefetch" href="//www.kahla.app">
<link rel="dns-prefetch" href="//server.kahla.app">
<link rel="preconnect" href="//www.kahla.app">
Expand Down
Loading

0 comments on commit 4e162ad

Please sign in to comment.