stream-chat-angular 5.0.0 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/version.d.ts +1 -1
- package/esm2020/assets/version.mjs +2 -2
- package/esm2020/lib/avatar/avatar.component.mjs +4 -1
- package/esm2020/lib/channel-list/channel-list.component.mjs +2 -2
- package/esm2020/lib/channel.service.mjs +10 -26
- package/esm2020/lib/chat-client.service.mjs +2 -3
- package/esm2020/lib/message-actions.service.mjs +4 -4
- package/esm2020/lib/message-list/message-list.component.mjs +181 -249
- package/esm2020/lib/types.mjs +1 -1
- package/esm2020/lib/virtualized-list.service.mjs +271 -0
- package/esm2020/lib/virtualized-message-list.service.mjs +73 -0
- package/esm2020/lib/voice-recording/voice-recording.component.mjs +2 -2
- package/esm2020/public-api.mjs +3 -1
- package/fesm2015/stream-chat-angular.mjs +550 -288
- package/fesm2015/stream-chat-angular.mjs.map +1 -1
- package/fesm2020/stream-chat-angular.mjs +536 -277
- package/fesm2020/stream-chat-angular.mjs.map +1 -1
- package/lib/avatar/avatar.component.d.ts +3 -2
- package/lib/channel-list/channel-list.component.d.ts +1 -1
- package/lib/channel.service.d.ts +6 -12
- package/lib/message-list/message-list.component.d.ts +12 -18
- package/lib/types.d.ts +7 -0
- package/lib/virtualized-list.service.d.ts +58 -0
- package/lib/virtualized-message-list.service.d.ts +15 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
- package/src/assets/styles/css/index.css +1 -1
- package/src/assets/styles/css/index.layout.css +1 -1
- package/src/assets/styles/scss/LoadingIndicator/LoadingIndicator-layout.scss +16 -0
- package/src/assets/version.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { Injectable, Component, Input, EventEmitter, Output, ViewChild, HostBinding, ChangeDetectionStrategy, InjectionToken, Directive, Inject, NgModule } from '@angular/core';
|
|
4
|
-
import { BehaviorSubject, ReplaySubject, combineLatest, take as take$1, Subject, timer } from 'rxjs';
|
|
4
|
+
import { BehaviorSubject, ReplaySubject, combineLatest, take as take$1, Subject, timer, merge, switchMap, distinctUntilChanged, pairwise, filter as filter$1, of, map as map$1 } from 'rxjs';
|
|
5
5
|
import { StreamChat } from 'stream-chat';
|
|
6
6
|
import { take, shareReplay, map, first, filter, tap, debounceTime, throttleTime } from 'rxjs/operators';
|
|
7
7
|
import { v4 } from 'uuid';
|
|
@@ -20,7 +20,7 @@ import transliterate from '@stream-io/transliterate';
|
|
|
20
20
|
import * as i8$1 from 'angular-mentions';
|
|
21
21
|
import { MentionModule } from 'angular-mentions';
|
|
22
22
|
|
|
23
|
-
const version = '5.
|
|
23
|
+
const version = '5.1.1';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
|
|
@@ -252,9 +252,8 @@ class ChatClientService {
|
|
|
252
252
|
{ id: { $autocomplete: searchTerm } },
|
|
253
253
|
{ name: { $autocomplete: searchTerm } },
|
|
254
254
|
],
|
|
255
|
-
id: { $ne: this.chatClient.userID },
|
|
256
255
|
}); // TODO: find out why we need this typecast
|
|
257
|
-
return result.users;
|
|
256
|
+
return result.users.filter((u) => { var _a, _b; return u.id !== ((_b = (_a = this.chatClient) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id); });
|
|
258
257
|
});
|
|
259
258
|
}
|
|
260
259
|
updatePendingInvites(e) {
|
|
@@ -437,6 +436,7 @@ class ChannelService {
|
|
|
437
436
|
this.chatClientService = chatClientService;
|
|
438
437
|
this.ngZone = ngZone;
|
|
439
438
|
this.notificationService = notificationService;
|
|
439
|
+
this.messagePageSize = 25;
|
|
440
440
|
this.channelsSubject = new BehaviorSubject(undefined);
|
|
441
441
|
this.activeChannelSubject = new BehaviorSubject(undefined);
|
|
442
442
|
this.activeChannelMessagesSubject = new BehaviorSubject([]);
|
|
@@ -448,7 +448,6 @@ class ChannelService {
|
|
|
448
448
|
this.activeThreadMessagesSubject = new BehaviorSubject([]);
|
|
449
449
|
this.jumpToMessageSubject = new BehaviorSubject({ id: undefined, parentId: undefined });
|
|
450
450
|
this.latestMessageDateByUserByChannelsSubject = new BehaviorSubject({});
|
|
451
|
-
this.messagePageSize = 25;
|
|
452
451
|
this.attachmentMaxSizeFallbackInMB = 100;
|
|
453
452
|
this.messageToQuoteSubject = new BehaviorSubject(undefined);
|
|
454
453
|
this.usersTypingInChannelSubject = new BehaviorSubject([]);
|
|
@@ -556,23 +555,6 @@ class ChannelService {
|
|
|
556
555
|
.asObservable()
|
|
557
556
|
.pipe(shareReplay(1));
|
|
558
557
|
}
|
|
559
|
-
/**
|
|
560
|
-
* internal
|
|
561
|
-
*/
|
|
562
|
-
removeOldMessageFromMessageList() {
|
|
563
|
-
const channel = this.activeChannelSubject.getValue();
|
|
564
|
-
const channelMessages = channel === null || channel === void 0 ? void 0 : channel.state.latestMessages;
|
|
565
|
-
const targetLength = Math.ceil(ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST / 2);
|
|
566
|
-
if (!channel ||
|
|
567
|
-
!channelMessages ||
|
|
568
|
-
channelMessages !== (channel === null || channel === void 0 ? void 0 : channel.state.latestMessages) ||
|
|
569
|
-
channelMessages.length <= targetLength) {
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
const messages = channelMessages;
|
|
573
|
-
messages.splice(0, messages.length - targetLength);
|
|
574
|
-
this.activeChannelMessagesSubject.next(messages);
|
|
575
|
-
}
|
|
576
558
|
/**
|
|
577
559
|
* If set to false, read events won't be sent as new messages are received. If set to true active channel (if any) will immediately be marked as read.
|
|
578
560
|
*/
|
|
@@ -1031,9 +1013,8 @@ class ChannelService {
|
|
|
1031
1013
|
}
|
|
1032
1014
|
const result = yield activeChannel.queryMembers({
|
|
1033
1015
|
name: { $autocomplete: searchTerm },
|
|
1034
|
-
id: { $ne: this.chatClientService.chatClient.userID },
|
|
1035
1016
|
}); // TODO: find out why we need typecast here
|
|
1036
|
-
return
|
|
1017
|
+
return result.members.filter((m) => { var _a, _b; return m.user_id !== ((_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id); });
|
|
1037
1018
|
}
|
|
1038
1019
|
});
|
|
1039
1020
|
}
|
|
@@ -1469,6 +1450,12 @@ class ChannelService {
|
|
|
1469
1450
|
get activeChannelMessages() {
|
|
1470
1451
|
return this.activeChannelMessagesSubject.getValue() || [];
|
|
1471
1452
|
}
|
|
1453
|
+
/**
|
|
1454
|
+
* The current thread replies
|
|
1455
|
+
*/
|
|
1456
|
+
get activeChannelThreadReplies() {
|
|
1457
|
+
return this.activeThreadMessagesSubject.getValue() || [];
|
|
1458
|
+
}
|
|
1472
1459
|
/**
|
|
1473
1460
|
* Get the last 1200 reactions of a message in the current active channel. If you need to fetch more reactions please use the [following endpoint](https://getstream.io/chat/docs/javascript/send_reaction/?language=javascript#paginating-reactions).
|
|
1474
1461
|
* @param messageId
|
|
@@ -1556,7 +1543,7 @@ class ChannelService {
|
|
|
1556
1543
|
return;
|
|
1557
1544
|
}
|
|
1558
1545
|
const messageIndex = messages.findIndex((m) => { var _a; return m.id === ((_a = event === null || event === void 0 ? void 0 : event.message) === null || _a === void 0 ? void 0 : _a.id); });
|
|
1559
|
-
if (messageIndex !== -1) {
|
|
1546
|
+
if (messageIndex !== -1 || event.type === 'message.deleted') {
|
|
1560
1547
|
isThreadReply
|
|
1561
1548
|
? this.activeThreadMessagesSubject.next([...messages])
|
|
1562
1549
|
: this.activeChannelMessagesSubject.next([...messages]);
|
|
@@ -1944,10 +1931,6 @@ class ChannelService {
|
|
|
1944
1931
|
});
|
|
1945
1932
|
}
|
|
1946
1933
|
}
|
|
1947
|
-
/**
|
|
1948
|
-
* @internal
|
|
1949
|
-
*/
|
|
1950
|
-
ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST = 250;
|
|
1951
1934
|
/**
|
|
1952
1935
|
* @internal
|
|
1953
1936
|
*/
|
|
@@ -2725,6 +2708,9 @@ class AvatarComponent {
|
|
|
2725
2708
|
this.setFallbackChannelImage();
|
|
2726
2709
|
}
|
|
2727
2710
|
}
|
|
2711
|
+
ngOnDestroy() {
|
|
2712
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
2713
|
+
}
|
|
2728
2714
|
setFallbackChannelImage() {
|
|
2729
2715
|
if (this.type !== 'channel') {
|
|
2730
2716
|
this.fallbackChannelImage = undefined;
|
|
@@ -3204,7 +3190,7 @@ class MessageActionsService {
|
|
|
3204
3190
|
actionHandler: (message) => {
|
|
3205
3191
|
void this.channelService.markMessageUnread(message.id);
|
|
3206
3192
|
},
|
|
3207
|
-
isVisible: (enabledActions,
|
|
3193
|
+
isVisible: (enabledActions, _, message) => enabledActions.indexOf('read-events') !== -1 && !message.parent_id,
|
|
3208
3194
|
},
|
|
3209
3195
|
{
|
|
3210
3196
|
actionName: 'quote',
|
|
@@ -3220,7 +3206,7 @@ class MessageActionsService {
|
|
|
3220
3206
|
actionHandler: (message) => {
|
|
3221
3207
|
void this.channelService.setAsActiveParentMessage(message);
|
|
3222
3208
|
},
|
|
3223
|
-
isVisible: (enabledActions,
|
|
3209
|
+
isVisible: (enabledActions, _, message) => enabledActions.indexOf('send-reply') !== -1 && !message.parent_id,
|
|
3224
3210
|
},
|
|
3225
3211
|
{
|
|
3226
3212
|
actionName: 'pin',
|
|
@@ -3241,7 +3227,7 @@ class MessageActionsService {
|
|
|
3241
3227
|
yield this.chatClientService.flagMessage(message.id);
|
|
3242
3228
|
this.notificationService.addTemporaryNotification('streamChat.Message has been successfully flagged', 'success');
|
|
3243
3229
|
}
|
|
3244
|
-
catch (
|
|
3230
|
+
catch (error) {
|
|
3245
3231
|
this.notificationService.addTemporaryNotification('streamChat.Error adding flag');
|
|
3246
3232
|
}
|
|
3247
3233
|
}),
|
|
@@ -4158,7 +4144,7 @@ class ChannelListComponent {
|
|
|
4158
4144
|
this.isLoadingMoreChannels = false;
|
|
4159
4145
|
});
|
|
4160
4146
|
}
|
|
4161
|
-
trackByChannelId(
|
|
4147
|
+
trackByChannelId(_, item) {
|
|
4162
4148
|
return item.cid;
|
|
4163
4149
|
}
|
|
4164
4150
|
}
|
|
@@ -4408,7 +4394,7 @@ class VoiceRecordingComponent {
|
|
|
4408
4394
|
: this.audioElement.nativeElement.pause();
|
|
4409
4395
|
this.isError = false;
|
|
4410
4396
|
}
|
|
4411
|
-
catch (
|
|
4397
|
+
catch (error) {
|
|
4412
4398
|
this.isError = true;
|
|
4413
4399
|
}
|
|
4414
4400
|
});
|
|
@@ -6365,6 +6351,350 @@ const isOnSameDay = (date1, date2) => {
|
|
|
6365
6351
|
date1.getDate() === date2.getDate());
|
|
6366
6352
|
};
|
|
6367
6353
|
|
|
6354
|
+
/**
|
|
6355
|
+
* The `VirtualizedListService` removes items from a list that are not currently displayed. This is a high-level overview of how it works:
|
|
6356
|
+
* - Create a new instance for each list that needs virtualization
|
|
6357
|
+
* - Input: Provide a reactive stream that emits all items in the list
|
|
6358
|
+
* - Input: Provide a reactive stream that emit the current scroll position (top, middle or bottom)
|
|
6359
|
+
* - Input: maximum number of items that are allowed in the list (in practice the service can make the virtualized list half this number, you should take this into account when choosing the value)
|
|
6360
|
+
* - Output: The service will emit the current list of displayed items via the virtualized items reactive stream
|
|
6361
|
+
* - For simplicity, the service won't track the height of the items, nor it needs an exact scroll location -> this is how removing items work:
|
|
6362
|
+
* - If scroll location is bottom/top items around the current bottom/top item will be emitted in the virtualized items stream
|
|
6363
|
+
* - If scroll location is middle, the service won't remove items, if new items are received, those will be appended to the virtualized list (this means that in theory the list can grow very big if a lot of new items are received while the user is scrolled somewhere, this is a trade-off for the simplicity of no height tracking)
|
|
6364
|
+
* - Since there is no height tracking, you should make sure to provide a maximum number that is big enough to fill the biggest expected screen size twice
|
|
6365
|
+
* - If the user scrolls to the bottom/top and there are no more local items to show, the service will trigger a query to load more items
|
|
6366
|
+
* - Input: you should provide the page size to use, in order for the service to determine if loading is necessary
|
|
6367
|
+
*
|
|
6368
|
+
* The `VirtualizedMessageListService` provides an implementation for the message list component.
|
|
6369
|
+
*/
|
|
6370
|
+
class VirtualizedListService {
|
|
6371
|
+
constructor(allItems$, scrollPosition$, jumpToItem$, pageSize = 25, maxItemCount = pageSize * 4) {
|
|
6372
|
+
this.allItems$ = allItems$;
|
|
6373
|
+
this.scrollPosition$ = scrollPosition$;
|
|
6374
|
+
this.jumpToItem$ = jumpToItem$;
|
|
6375
|
+
this.pageSize = pageSize;
|
|
6376
|
+
this.maxItemCount = maxItemCount;
|
|
6377
|
+
this.queryStateSubject = new BehaviorSubject({
|
|
6378
|
+
state: 'success',
|
|
6379
|
+
});
|
|
6380
|
+
this.bufferOnTop = 0;
|
|
6381
|
+
this.bufferOnBottom = 0;
|
|
6382
|
+
this.loadFromBuffer$ = new Subject();
|
|
6383
|
+
this.virtualizedItemsSubject = new BehaviorSubject([]);
|
|
6384
|
+
this.subscriptions = [];
|
|
6385
|
+
this.virtualizedItems$ = this.virtualizedItemsSubject.asObservable();
|
|
6386
|
+
this.queryState$ = this.queryStateSubject.asObservable();
|
|
6387
|
+
this.subscriptions.push(this.virtualizedItems$.subscribe((virtaluzedItems) => {
|
|
6388
|
+
this.allItems$.pipe(take$1(1)).subscribe((allItems) => {
|
|
6389
|
+
if (virtaluzedItems.length === allItems.length) {
|
|
6390
|
+
this.bufferOnTop = 0;
|
|
6391
|
+
this.bufferOnBottom = 0;
|
|
6392
|
+
}
|
|
6393
|
+
else if (virtaluzedItems.length === 0) {
|
|
6394
|
+
this.bufferOnTop = allItems.length;
|
|
6395
|
+
this.bufferOnBottom = 0;
|
|
6396
|
+
}
|
|
6397
|
+
else {
|
|
6398
|
+
this.bufferOnTop = allItems.indexOf(virtaluzedItems[0]);
|
|
6399
|
+
this.bufferOnBottom =
|
|
6400
|
+
allItems.length -
|
|
6401
|
+
allItems.indexOf(virtaluzedItems[virtaluzedItems.length - 1]) -
|
|
6402
|
+
1;
|
|
6403
|
+
}
|
|
6404
|
+
});
|
|
6405
|
+
}));
|
|
6406
|
+
this.subscriptions.push(merge(this.allItems$, this.loadFromBuffer$)
|
|
6407
|
+
.pipe(switchMap(() => {
|
|
6408
|
+
return combineLatest([
|
|
6409
|
+
this.allItems$.pipe(take$1(1)),
|
|
6410
|
+
this.scrollPosition$.pipe(take$1(1)),
|
|
6411
|
+
]);
|
|
6412
|
+
}))
|
|
6413
|
+
.subscribe(([items, scrollPosition]) => {
|
|
6414
|
+
if (scrollPosition === 'middle') {
|
|
6415
|
+
return;
|
|
6416
|
+
}
|
|
6417
|
+
const currentItems = this.virtualizedItemsSubject.getValue();
|
|
6418
|
+
if (items.length <= this.maxItemCount) {
|
|
6419
|
+
this.virtualizedItemsSubject.next(items);
|
|
6420
|
+
}
|
|
6421
|
+
else {
|
|
6422
|
+
let startIndex = 0;
|
|
6423
|
+
let endIndex = undefined;
|
|
6424
|
+
const numberOfItemsToRemove = items.length - Math.round(this.maxItemCount / 2);
|
|
6425
|
+
const numberOfItemsAfterRemove = items.length - numberOfItemsToRemove;
|
|
6426
|
+
switch (scrollPosition) {
|
|
6427
|
+
case 'top':
|
|
6428
|
+
if (currentItems.length > 0) {
|
|
6429
|
+
const middleIndex = items.findIndex((i) => this.isEqual(i, currentItems[0]));
|
|
6430
|
+
if (middleIndex !== -1) {
|
|
6431
|
+
startIndex = Math.max(0, middleIndex - Math.ceil(numberOfItemsAfterRemove / 2));
|
|
6432
|
+
endIndex = startIndex + numberOfItemsAfterRemove;
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6435
|
+
else {
|
|
6436
|
+
endIndex = numberOfItemsAfterRemove;
|
|
6437
|
+
}
|
|
6438
|
+
break;
|
|
6439
|
+
case 'bottom':
|
|
6440
|
+
if (currentItems.length > 0) {
|
|
6441
|
+
const middleIndex = items.findIndex((i) => this.isEqual(i, currentItems[currentItems.length - 1]));
|
|
6442
|
+
if (middleIndex !== -1) {
|
|
6443
|
+
endIndex = Math.min(items.length, middleIndex + Math.floor(numberOfItemsAfterRemove / 2) + 1);
|
|
6444
|
+
startIndex = endIndex - numberOfItemsAfterRemove;
|
|
6445
|
+
}
|
|
6446
|
+
}
|
|
6447
|
+
else {
|
|
6448
|
+
startIndex = items.length - numberOfItemsAfterRemove;
|
|
6449
|
+
}
|
|
6450
|
+
break;
|
|
6451
|
+
}
|
|
6452
|
+
const virtualizedItems = items.slice(startIndex, endIndex);
|
|
6453
|
+
this.virtualizedItemsSubject.next(virtualizedItems);
|
|
6454
|
+
}
|
|
6455
|
+
}));
|
|
6456
|
+
this.subscriptions.push(this.scrollPosition$
|
|
6457
|
+
.pipe(distinctUntilChanged())
|
|
6458
|
+
.subscribe((position) => {
|
|
6459
|
+
if (this.queryStateSubject.getValue().state === `loading-${position}`) {
|
|
6460
|
+
return;
|
|
6461
|
+
}
|
|
6462
|
+
if (position === 'top') {
|
|
6463
|
+
if (this.bufferOnTop < this.pageSize) {
|
|
6464
|
+
void this.loadMore(position);
|
|
6465
|
+
}
|
|
6466
|
+
else {
|
|
6467
|
+
this.loadMoreFromBuffer('top');
|
|
6468
|
+
}
|
|
6469
|
+
}
|
|
6470
|
+
else if (position === 'bottom') {
|
|
6471
|
+
if (this.bufferOnBottom < this.pageSize) {
|
|
6472
|
+
void this.loadMore(position);
|
|
6473
|
+
}
|
|
6474
|
+
else {
|
|
6475
|
+
this.loadMoreFromBuffer('bottom');
|
|
6476
|
+
}
|
|
6477
|
+
}
|
|
6478
|
+
}));
|
|
6479
|
+
this.subscriptions.push(this.allItems$
|
|
6480
|
+
.pipe(pairwise(), filter$1(() => {
|
|
6481
|
+
let scrollPosition;
|
|
6482
|
+
this.scrollPosition$
|
|
6483
|
+
.pipe(take$1(1))
|
|
6484
|
+
.subscribe((s) => (scrollPosition = s));
|
|
6485
|
+
return scrollPosition === 'middle';
|
|
6486
|
+
}))
|
|
6487
|
+
.subscribe(([prevItems, currentItems]) => {
|
|
6488
|
+
if (currentItems.length < this.maxItemCount ||
|
|
6489
|
+
this.virtualizedItems.length === 0) {
|
|
6490
|
+
this.virtualizedItemsSubject.next(currentItems);
|
|
6491
|
+
}
|
|
6492
|
+
else {
|
|
6493
|
+
const currentFirstItem = this.virtualizedItems[0];
|
|
6494
|
+
const currentLastItem = this.virtualizedItems[this.virtualizedItems.length - 1];
|
|
6495
|
+
const prevStartIndex = prevItems.findIndex((i) => this.isEqual(i, currentFirstItem));
|
|
6496
|
+
const prevEndIndex = prevItems.findIndex((i) => this.isEqual(i, currentLastItem));
|
|
6497
|
+
const isStartRemainedSame = currentItems[prevStartIndex]
|
|
6498
|
+
? this.isEqual(currentItems[prevStartIndex], currentFirstItem)
|
|
6499
|
+
: false;
|
|
6500
|
+
const isEndRemainedSame = currentItems[prevEndIndex]
|
|
6501
|
+
? this.isEqual(currentItems[prevEndIndex], currentLastItem)
|
|
6502
|
+
: false;
|
|
6503
|
+
const hasNewItemsBottom = prevEndIndex === prevItems.length - 1 && isEndRemainedSame
|
|
6504
|
+
? prevItems.length !== currentItems.length
|
|
6505
|
+
: false;
|
|
6506
|
+
if (isStartRemainedSame && isEndRemainedSame) {
|
|
6507
|
+
const endIndex = hasNewItemsBottom ? undefined : prevEndIndex + 1;
|
|
6508
|
+
this.virtualizedItemsSubject.next(currentItems.slice(prevStartIndex, endIndex));
|
|
6509
|
+
}
|
|
6510
|
+
let currentStartIndex = isStartRemainedSame ? prevStartIndex : -1;
|
|
6511
|
+
let currentEndIndex = isEndRemainedSame ? prevEndIndex : -1;
|
|
6512
|
+
if (!isStartRemainedSame) {
|
|
6513
|
+
currentStartIndex = currentItems.findIndex((i) => this.isEqual(i, currentFirstItem));
|
|
6514
|
+
}
|
|
6515
|
+
if (!isEndRemainedSame) {
|
|
6516
|
+
currentEndIndex = currentItems.findIndex((i) => this.isEqual(i, currentLastItem));
|
|
6517
|
+
}
|
|
6518
|
+
const hasNewItemsTop = prevStartIndex === 0 && !isStartRemainedSame
|
|
6519
|
+
? currentStartIndex !== 0
|
|
6520
|
+
: false;
|
|
6521
|
+
if (currentStartIndex !== -1 && currentEndIndex !== -1) {
|
|
6522
|
+
const startIndex = hasNewItemsTop ? 0 : currentStartIndex;
|
|
6523
|
+
this.virtualizedItemsSubject.next(currentItems.slice(startIndex, currentEndIndex + 1));
|
|
6524
|
+
}
|
|
6525
|
+
else {
|
|
6526
|
+
if (currentStartIndex === -1 && currentEndIndex !== -1) {
|
|
6527
|
+
currentStartIndex = Math.max(0, currentEndIndex - (prevEndIndex - prevStartIndex));
|
|
6528
|
+
}
|
|
6529
|
+
if (currentEndIndex === -1 && currentStartIndex !== -1) {
|
|
6530
|
+
currentEndIndex = Math.min(currentItems.length - 1, currentStartIndex + (prevEndIndex - prevStartIndex));
|
|
6531
|
+
}
|
|
6532
|
+
this.virtualizedItemsSubject.next(currentItems.slice(currentStartIndex, currentEndIndex + 1));
|
|
6533
|
+
}
|
|
6534
|
+
}
|
|
6535
|
+
}));
|
|
6536
|
+
if (this.jumpToItem$) {
|
|
6537
|
+
this.subscriptions.push(this.jumpToItem$
|
|
6538
|
+
.pipe(switchMap((jumpToItem) => combineLatest([this.allItems$.pipe(take$1(1)), of(jumpToItem)])))
|
|
6539
|
+
.subscribe(([allItems, jumpToItem]) => {
|
|
6540
|
+
if (jumpToItem.item) {
|
|
6541
|
+
if (allItems.length < this.maxItemCount) {
|
|
6542
|
+
this.virtualizedItemsSubject.next(allItems);
|
|
6543
|
+
}
|
|
6544
|
+
else {
|
|
6545
|
+
const itemIndex = allItems.findIndex((i) =>
|
|
6546
|
+
// @ts-expect-error TODO: do we know a better typing here?
|
|
6547
|
+
this.isEqual(i, jumpToItem.item));
|
|
6548
|
+
if (itemIndex === -1) {
|
|
6549
|
+
return;
|
|
6550
|
+
}
|
|
6551
|
+
else {
|
|
6552
|
+
const position = jumpToItem.position || 'middle';
|
|
6553
|
+
const numberOfItemsToRemove = allItems.length - Math.round(this.maxItemCount / 2);
|
|
6554
|
+
const numberOfItemsAfterRemove = allItems.length - numberOfItemsToRemove;
|
|
6555
|
+
let startIndex = -1;
|
|
6556
|
+
let endIndex = -1;
|
|
6557
|
+
switch (position) {
|
|
6558
|
+
case 'top':
|
|
6559
|
+
startIndex = itemIndex;
|
|
6560
|
+
endIndex = Math.min(allItems.length, startIndex + numberOfItemsAfterRemove);
|
|
6561
|
+
break;
|
|
6562
|
+
case 'bottom':
|
|
6563
|
+
endIndex = itemIndex + 1;
|
|
6564
|
+
startIndex = Math.max(0, endIndex - numberOfItemsAfterRemove);
|
|
6565
|
+
break;
|
|
6566
|
+
case 'middle': {
|
|
6567
|
+
const itemsOnTop = itemIndex;
|
|
6568
|
+
const itemsOnBottom = allItems.length - itemIndex;
|
|
6569
|
+
if (itemsOnTop < Math.ceil(numberOfItemsAfterRemove / 2)) {
|
|
6570
|
+
startIndex = 0;
|
|
6571
|
+
}
|
|
6572
|
+
if (itemsOnBottom <
|
|
6573
|
+
Math.floor(numberOfItemsAfterRemove / 2) + 1) {
|
|
6574
|
+
endIndex = allItems.length;
|
|
6575
|
+
}
|
|
6576
|
+
if (startIndex === -1) {
|
|
6577
|
+
if (endIndex !== -1) {
|
|
6578
|
+
startIndex = endIndex - numberOfItemsAfterRemove;
|
|
6579
|
+
}
|
|
6580
|
+
else {
|
|
6581
|
+
startIndex =
|
|
6582
|
+
itemIndex - Math.ceil(numberOfItemsAfterRemove / 2);
|
|
6583
|
+
}
|
|
6584
|
+
}
|
|
6585
|
+
if (endIndex === -1) {
|
|
6586
|
+
endIndex = startIndex + numberOfItemsAfterRemove;
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
}
|
|
6590
|
+
this.virtualizedItemsSubject.next(allItems.slice(startIndex, endIndex));
|
|
6591
|
+
}
|
|
6592
|
+
}
|
|
6593
|
+
}
|
|
6594
|
+
}));
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
/**
|
|
6598
|
+
* The current value of virtualized items
|
|
6599
|
+
*/
|
|
6600
|
+
get virtualizedItems() {
|
|
6601
|
+
return this.virtualizedItemsSubject.getValue();
|
|
6602
|
+
}
|
|
6603
|
+
/**
|
|
6604
|
+
* Remove all subscriptions, call this once you're done using an instance of this service
|
|
6605
|
+
*/
|
|
6606
|
+
dispose() {
|
|
6607
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
6608
|
+
}
|
|
6609
|
+
loadMoreFromBuffer(_) {
|
|
6610
|
+
this.loadFromBuffer$.next();
|
|
6611
|
+
}
|
|
6612
|
+
loadMore(direction) {
|
|
6613
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
6614
|
+
this.queryStateSubject.next({ state: `loading-${direction}` });
|
|
6615
|
+
try {
|
|
6616
|
+
yield this.query(direction);
|
|
6617
|
+
this.queryStateSubject.next({ state: 'success' });
|
|
6618
|
+
}
|
|
6619
|
+
catch (e) {
|
|
6620
|
+
this.queryStateSubject.next({ state: 'error', error: e });
|
|
6621
|
+
}
|
|
6622
|
+
});
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
|
|
6626
|
+
/**
|
|
6627
|
+
* The `VirtualizedMessageListService` removes messages from the message list that are currently not in view
|
|
6628
|
+
*/
|
|
6629
|
+
class VirtualizedMessageListService extends VirtualizedListService {
|
|
6630
|
+
constructor(mode, scrollPosition$, channelService) {
|
|
6631
|
+
const jumpToMessage$ = channelService.jumpToMessage$.pipe(map$1((jumpToMessage) => {
|
|
6632
|
+
var _a;
|
|
6633
|
+
let result = {
|
|
6634
|
+
item: undefined,
|
|
6635
|
+
};
|
|
6636
|
+
let targetMessageId;
|
|
6637
|
+
if (mode === 'main') {
|
|
6638
|
+
targetMessageId = jumpToMessage.parentId
|
|
6639
|
+
? jumpToMessage.parentId
|
|
6640
|
+
: jumpToMessage.id;
|
|
6641
|
+
}
|
|
6642
|
+
else {
|
|
6643
|
+
targetMessageId = jumpToMessage.parentId
|
|
6644
|
+
? jumpToMessage.id
|
|
6645
|
+
: undefined;
|
|
6646
|
+
}
|
|
6647
|
+
if (targetMessageId) {
|
|
6648
|
+
const messages = mode === 'main'
|
|
6649
|
+
? channelService.activeChannelMessages
|
|
6650
|
+
: channelService.activeChannelThreadReplies;
|
|
6651
|
+
const id = targetMessageId === 'latest'
|
|
6652
|
+
? (_a = messages[messages.length - 1]) === null || _a === void 0 ? void 0 : _a.id
|
|
6653
|
+
: targetMessageId;
|
|
6654
|
+
if (id) {
|
|
6655
|
+
result = {
|
|
6656
|
+
item: { id },
|
|
6657
|
+
position: jumpToMessage.id === 'latest' ? 'bottom' : 'middle',
|
|
6658
|
+
};
|
|
6659
|
+
}
|
|
6660
|
+
channelService.clearMessageJump();
|
|
6661
|
+
}
|
|
6662
|
+
return result;
|
|
6663
|
+
}));
|
|
6664
|
+
const messages$ = mode === 'main'
|
|
6665
|
+
? channelService.activeChannelMessages$
|
|
6666
|
+
: channelService.activeThreadMessages$;
|
|
6667
|
+
super(messages$, scrollPosition$, jumpToMessage$, channelService.messagePageSize);
|
|
6668
|
+
this.mode = mode;
|
|
6669
|
+
this.channelService = channelService;
|
|
6670
|
+
this.isEqual = (t1, t2) => t1.id === t2.id;
|
|
6671
|
+
this.query = (direction) => {
|
|
6672
|
+
const request = this.mode === 'main'
|
|
6673
|
+
? (direction) => this.channelService.loadMoreMessages(direction)
|
|
6674
|
+
: (direction) => this.channelService.loadMoreThreadReplies(direction);
|
|
6675
|
+
const result = request(direction === 'top' ? 'older' : 'newer');
|
|
6676
|
+
if (result) {
|
|
6677
|
+
return result;
|
|
6678
|
+
}
|
|
6679
|
+
else {
|
|
6680
|
+
this.queryStateSubject.next({ state: 'success' });
|
|
6681
|
+
if ((direction === 'top' && this.bufferOnTop > 0) ||
|
|
6682
|
+
(direction === 'bottom' && this.bufferOnBottom > 0)) {
|
|
6683
|
+
this.loadFromBuffer$.next();
|
|
6684
|
+
}
|
|
6685
|
+
return Promise.resolve();
|
|
6686
|
+
}
|
|
6687
|
+
};
|
|
6688
|
+
}
|
|
6689
|
+
loadMoreFromBuffer(direction) {
|
|
6690
|
+
this.queryStateSubject.next({ state: `loading-${direction}` });
|
|
6691
|
+
setTimeout(() => {
|
|
6692
|
+
this.loadFromBuffer$.next();
|
|
6693
|
+
this.queryStateSubject.next({ state: 'success' });
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
|
|
6368
6698
|
/**
|
|
6369
6699
|
* The `MessageList` component renders a scrollable list of messages.
|
|
6370
6700
|
*/
|
|
@@ -6415,10 +6745,6 @@ class MessageListComponent {
|
|
|
6415
6745
|
* You can turn on and off the loading indicator that signals to users that more messages are being loaded to the message list
|
|
6416
6746
|
*/
|
|
6417
6747
|
this.displayLoadingIndicator = true;
|
|
6418
|
-
/**
|
|
6419
|
-
* @internal
|
|
6420
|
-
*/
|
|
6421
|
-
this.limitNumberOfMessagesInList = true;
|
|
6422
6748
|
this.emptyMainMessageListTemplate = null;
|
|
6423
6749
|
this.emptyThreadMessageListTemplate = null;
|
|
6424
6750
|
this.enabledMessageActions = [];
|
|
@@ -6426,17 +6752,20 @@ class MessageListComponent {
|
|
|
6426
6752
|
this.newMessageCountWhileBeingScrolled = 0;
|
|
6427
6753
|
this.groupStyles = [];
|
|
6428
6754
|
this.isNextMessageOnSeparateDate = [];
|
|
6429
|
-
this.
|
|
6755
|
+
this.loadingState = 'idle';
|
|
6430
6756
|
this.isUnreadNotificationVisible = true;
|
|
6431
6757
|
this.isJumpingToLatestUnreadMessage = false;
|
|
6432
6758
|
this.isJumpToLatestButtonVisible = true;
|
|
6759
|
+
this.isJumpingToMessage = false;
|
|
6433
6760
|
this.scroll$ = new Subject();
|
|
6761
|
+
this.isNewMessageSentByUser = false;
|
|
6434
6762
|
this.subscriptions = [];
|
|
6435
6763
|
this.isLatestMessageInList = true;
|
|
6436
6764
|
this.parsedDates = new Map();
|
|
6437
6765
|
this.isViewInited = false;
|
|
6438
6766
|
this.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
6439
6767
|
this.forceRepaintSubject = new Subject();
|
|
6768
|
+
this.scrollPosition$ = new BehaviorSubject('bottom');
|
|
6440
6769
|
this.messageNotificationJumpClicked = () => {
|
|
6441
6770
|
this.jumpToFirstUnreadMessage();
|
|
6442
6771
|
this.isUnreadNotificationVisible = false;
|
|
@@ -6455,8 +6784,7 @@ class MessageListComponent {
|
|
|
6455
6784
|
this.forceRepaint();
|
|
6456
6785
|
}));
|
|
6457
6786
|
this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
|
|
6458
|
-
var _a, _b
|
|
6459
|
-
(_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `${(channel === null || channel === void 0 ? void 0 : channel.cid) || 'undefined'} selected`, { tags: `message list ${this.mode}` });
|
|
6787
|
+
var _a, _b;
|
|
6460
6788
|
let isNewChannel = false;
|
|
6461
6789
|
if (this.channelId !== (channel === null || channel === void 0 ? void 0 : channel.id)) {
|
|
6462
6790
|
isNewChannel = true;
|
|
@@ -6464,12 +6792,9 @@ class MessageListComponent {
|
|
|
6464
6792
|
clearTimeout(this.checkIfUnreadNotificationIsVisibleTimeout);
|
|
6465
6793
|
}
|
|
6466
6794
|
this.isUnreadNotificationVisible = false;
|
|
6467
|
-
(_e = (_d = (_c = this.chatClientService) === null || _c === void 0 ? void 0 : _c.chatClient) === null || _d === void 0 ? void 0 : _d.logger) === null || _e === void 0 ? void 0 : _e.call(_d, 'info', `new channel is different from prev channel, reseting scroll state`, { tags: `message list ${this.mode}` });
|
|
6468
6795
|
this.parsedDates = new Map();
|
|
6469
|
-
if (this.messageRemoveTimeout) {
|
|
6470
|
-
clearTimeout(this.messageRemoveTimeout);
|
|
6471
|
-
}
|
|
6472
6796
|
this.resetScrollState();
|
|
6797
|
+
this.setMessages$();
|
|
6473
6798
|
this.channelId = channel === null || channel === void 0 ? void 0 : channel.id;
|
|
6474
6799
|
if (this.isViewInited) {
|
|
6475
6800
|
this.cdRef.detectChanges();
|
|
@@ -6516,7 +6841,7 @@ class MessageListComponent {
|
|
|
6516
6841
|
this.cdRef.detectChanges();
|
|
6517
6842
|
}
|
|
6518
6843
|
}
|
|
6519
|
-
const capabilites = (
|
|
6844
|
+
const capabilites = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
|
|
6520
6845
|
const capabilitesString = [...(capabilites || [])].sort().join('');
|
|
6521
6846
|
const enabledActionsString = [...(this.enabledMessageActions || [])]
|
|
6522
6847
|
.sort()
|
|
@@ -6527,20 +6852,15 @@ class MessageListComponent {
|
|
|
6527
6852
|
this.cdRef.detectChanges();
|
|
6528
6853
|
}
|
|
6529
6854
|
}
|
|
6530
|
-
(
|
|
6855
|
+
(_b = this.newMessageSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
6531
6856
|
if (channel) {
|
|
6532
6857
|
this.newMessageSubscription = channel.on('message.new', (event) => {
|
|
6533
|
-
|
|
6534
|
-
if (!event.message ||
|
|
6535
|
-
channel.state.messages === channel.state.latestMessages ||
|
|
6536
|
-
this.mode === 'thread') {
|
|
6858
|
+
if (!event.message) {
|
|
6537
6859
|
return;
|
|
6538
6860
|
}
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
created_at: new Date(event.message.created_at || ''),
|
|
6543
|
-
});
|
|
6861
|
+
else {
|
|
6862
|
+
this.newMessageReceived(event.message);
|
|
6863
|
+
}
|
|
6544
6864
|
});
|
|
6545
6865
|
}
|
|
6546
6866
|
}));
|
|
@@ -6550,6 +6870,7 @@ class MessageListComponent {
|
|
|
6550
6870
|
message.id !== this.parentMessage.id &&
|
|
6551
6871
|
this.mode === 'thread') {
|
|
6552
6872
|
this.resetScrollState();
|
|
6873
|
+
this.setMessages$();
|
|
6553
6874
|
}
|
|
6554
6875
|
if (this.parentMessage === message) {
|
|
6555
6876
|
return;
|
|
@@ -6604,42 +6925,6 @@ class MessageListComponent {
|
|
|
6604
6925
|
this.cdRef.detectChanges();
|
|
6605
6926
|
}
|
|
6606
6927
|
}));
|
|
6607
|
-
this.subscriptions.push(this.channelService.jumpToMessage$
|
|
6608
|
-
.pipe(filter((config) => !!config.id))
|
|
6609
|
-
.subscribe((config) => {
|
|
6610
|
-
var _a, _b;
|
|
6611
|
-
let messageId = undefined;
|
|
6612
|
-
if (this.messageRemoveTimeout) {
|
|
6613
|
-
clearTimeout(this.messageRemoveTimeout);
|
|
6614
|
-
}
|
|
6615
|
-
if (this.mode === 'main') {
|
|
6616
|
-
messageId = config.parentId || config.id;
|
|
6617
|
-
}
|
|
6618
|
-
else if (config.parentId) {
|
|
6619
|
-
messageId = config.id;
|
|
6620
|
-
}
|
|
6621
|
-
(_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `Jumping to ${messageId || ''}`, { tags: `message list ${this.mode}` });
|
|
6622
|
-
if (messageId) {
|
|
6623
|
-
if (messageId === 'latest') {
|
|
6624
|
-
this.scrollToLatestMessage();
|
|
6625
|
-
if (this.isViewInited) {
|
|
6626
|
-
this.cdRef.detectChanges();
|
|
6627
|
-
}
|
|
6628
|
-
}
|
|
6629
|
-
else {
|
|
6630
|
-
if (this.isJumpingToLatestUnreadMessage) {
|
|
6631
|
-
this.scrollMessageIntoView(this.firstUnreadMessageId || messageId);
|
|
6632
|
-
this.highlightedMessageId =
|
|
6633
|
-
this.firstUnreadMessageId || messageId;
|
|
6634
|
-
}
|
|
6635
|
-
else {
|
|
6636
|
-
this.scrollMessageIntoView(messageId);
|
|
6637
|
-
this.highlightedMessageId = messageId;
|
|
6638
|
-
}
|
|
6639
|
-
}
|
|
6640
|
-
}
|
|
6641
|
-
this.channelService.clearMessageJump();
|
|
6642
|
-
}));
|
|
6643
6928
|
this.subscriptions.push(this.customTemplatesService.emptyMainMessageListPlaceholder$.subscribe((template) => {
|
|
6644
6929
|
const isChanged = this.emptyMainMessageListTemplate !== template;
|
|
6645
6930
|
this.emptyMainMessageListTemplate = template || null;
|
|
@@ -6659,6 +6944,7 @@ class MessageListComponent {
|
|
|
6659
6944
|
ngOnChanges(changes) {
|
|
6660
6945
|
var _a;
|
|
6661
6946
|
if (changes.mode || changes.direction) {
|
|
6947
|
+
this.resetScrollState();
|
|
6662
6948
|
this.setMessages$();
|
|
6663
6949
|
}
|
|
6664
6950
|
if (changes.direction) {
|
|
@@ -6670,56 +6956,33 @@ class MessageListComponent {
|
|
|
6670
6956
|
ngAfterViewInit() {
|
|
6671
6957
|
this.isViewInited = true;
|
|
6672
6958
|
this.ngZone.runOutsideAngular(() => {
|
|
6673
|
-
|
|
6959
|
+
var _a, _b;
|
|
6960
|
+
(_b = (_a = this.scrollContainer) === null || _a === void 0 ? void 0 : _a.nativeElement) === null || _b === void 0 ? void 0 : _b.addEventListener('scroll', () => this.scrolled());
|
|
6674
6961
|
});
|
|
6675
6962
|
}
|
|
6676
6963
|
ngAfterViewChecked() {
|
|
6677
|
-
var _a, _b
|
|
6678
|
-
if (this.
|
|
6679
|
-
|
|
6680
|
-
this.
|
|
6681
|
-
this.
|
|
6964
|
+
var _a, _b;
|
|
6965
|
+
if (this.isJumpingToMessage) {
|
|
6966
|
+
this.isNewMessageSentByUser = false;
|
|
6967
|
+
this.messageIdToAnchorTo = undefined;
|
|
6968
|
+
this.anchorMessageTopOffset = undefined;
|
|
6969
|
+
return;
|
|
6682
6970
|
}
|
|
6683
|
-
if (this.
|
|
6684
|
-
|
|
6685
|
-
(this.isNewMessageSentByUser || !this.isUserScrolled)) {
|
|
6686
|
-
this.isLatestMessageInList
|
|
6687
|
-
? this.scrollToTop()
|
|
6688
|
-
: this.jumpToLatestMessage();
|
|
6689
|
-
this.hasNewMessages = false;
|
|
6690
|
-
this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
|
|
6691
|
-
}
|
|
6971
|
+
if (this.messageIdToAnchorTo && this.loadingState === 'idle') {
|
|
6972
|
+
this.preserveScrollbarPosition();
|
|
6692
6973
|
}
|
|
6693
|
-
else
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
this.hasNewMessages = false;
|
|
6702
|
-
this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
|
|
6703
|
-
}
|
|
6704
|
-
else if (this.olderMassagesLoaded) {
|
|
6705
|
-
(_d = (_c = this.chatClientService.chatClient) === null || _c === void 0 ? void 0 : _c.logger) === null || _d === void 0 ? void 0 : _d.call(_c, 'info', `Older messages are loaded, we preserve the scroll position`, { tags: `message list ${this.mode}` });
|
|
6706
|
-
this.preserveScrollbarPosition();
|
|
6707
|
-
this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
|
|
6708
|
-
this.olderMassagesLoaded = false;
|
|
6709
|
-
}
|
|
6710
|
-
else if (this.getScrollPosition() !== 'bottom' &&
|
|
6711
|
-
!this.isUserScrolled &&
|
|
6712
|
-
!this.highlightedMessageId) {
|
|
6713
|
-
(_f = (_e = this.chatClientService.chatClient) === null || _e === void 0 ? void 0 : _e.logger) === null || _f === void 0 ? void 0 : _f.call(_e, 'info', `Container grew and user didn't scroll therefore we ${this.isLatestMessageInList ? 'scroll' : 'jump'} to latest message`, { tags: `message list ${this.mode}` });
|
|
6714
|
-
this.isLatestMessageInList
|
|
6715
|
-
? this.scrollToBottom()
|
|
6716
|
-
: this.jumpToLatestMessage();
|
|
6717
|
-
this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
|
|
6718
|
-
}
|
|
6974
|
+
else if ((!this.isUserScrolled &&
|
|
6975
|
+
((_a = this.scrollContainer.nativeElement) === null || _a === void 0 ? void 0 : _a.scrollHeight) >
|
|
6976
|
+
((_b = this.scrollContainer) === null || _b === void 0 ? void 0 : _b.nativeElement.clientHeight) &&
|
|
6977
|
+
this.getScrollPosition() !==
|
|
6978
|
+
(this.direction === 'bottom-to-top' ? 'bottom' : 'top')) ||
|
|
6979
|
+
(this.isUserScrolled && this.isNewMessageSentByUser)) {
|
|
6980
|
+
this.isNewMessageSentByUser = false;
|
|
6981
|
+
this.jumpToLatestMessage();
|
|
6719
6982
|
}
|
|
6720
6983
|
}
|
|
6721
6984
|
ngOnDestroy() {
|
|
6722
|
-
var _a
|
|
6985
|
+
var _a;
|
|
6723
6986
|
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
6724
6987
|
(_a = this.newMessageSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
6725
6988
|
if (this.scrollEndTimeout) {
|
|
@@ -6731,20 +6994,24 @@ class MessageListComponent {
|
|
|
6731
6994
|
if (this.jumpToLatestButtonVisibilityTimeout) {
|
|
6732
6995
|
clearTimeout(this.jumpToLatestButtonVisibilityTimeout);
|
|
6733
6996
|
}
|
|
6734
|
-
|
|
6735
|
-
clearTimeout(this.messageRemoveTimeout);
|
|
6736
|
-
}
|
|
6737
|
-
(_b = this.removeOldMessagesSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
6997
|
+
this.disposeVirtualizedList();
|
|
6738
6998
|
}
|
|
6739
|
-
trackByMessageId(
|
|
6999
|
+
trackByMessageId(_, item) {
|
|
6740
7000
|
return item.id;
|
|
6741
7001
|
}
|
|
6742
|
-
trackByUserId(
|
|
7002
|
+
trackByUserId(_, user) {
|
|
6743
7003
|
return user.id;
|
|
6744
7004
|
}
|
|
6745
7005
|
jumpToLatestMessage() {
|
|
6746
7006
|
var _a;
|
|
6747
|
-
|
|
7007
|
+
if (this.isLatestMessageInList) {
|
|
7008
|
+
this.direction === 'bottom-to-top'
|
|
7009
|
+
? this.scrollToBottom()
|
|
7010
|
+
: this.scrollToTop();
|
|
7011
|
+
}
|
|
7012
|
+
else {
|
|
7013
|
+
void this.channelService.jumpToMessage('latest', this.mode === 'thread' ? (_a = this.parentMessage) === null || _a === void 0 ? void 0 : _a.id : undefined);
|
|
7014
|
+
}
|
|
6748
7015
|
}
|
|
6749
7016
|
scrollToBottom() {
|
|
6750
7017
|
this.scrollContainer.nativeElement.scrollTop =
|
|
@@ -6757,7 +7024,7 @@ class MessageListComponent {
|
|
|
6757
7024
|
this.scrollContainer.nativeElement.scrollTop = 0;
|
|
6758
7025
|
}
|
|
6759
7026
|
scrolled() {
|
|
6760
|
-
var _a
|
|
7027
|
+
var _a;
|
|
6761
7028
|
if (this.scrollContainer.nativeElement.scrollHeight ===
|
|
6762
7029
|
this.scrollContainer.nativeElement.clientHeight) {
|
|
6763
7030
|
if (this.isJumpToLatestButtonVisible) {
|
|
@@ -6768,8 +7035,7 @@ class MessageListComponent {
|
|
|
6768
7035
|
return;
|
|
6769
7036
|
}
|
|
6770
7037
|
this.scroll$.next();
|
|
6771
|
-
|
|
6772
|
-
(_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `Scrolled - scroll position: ${scrollPosition}, container height: ${this.scrollContainer.nativeElement.scrollHeight}`, { tags: `message list ${this.mode}` });
|
|
7038
|
+
let scrollPosition = this.getScrollPosition();
|
|
6773
7039
|
const isUserScrolled = (this.direction === 'bottom-to-top'
|
|
6774
7040
|
? scrollPosition !== 'bottom'
|
|
6775
7041
|
: scrollPosition !== 'top') || !this.isLatestMessageInList;
|
|
@@ -6798,31 +7064,31 @@ class MessageListComponent {
|
|
|
6798
7064
|
}
|
|
6799
7065
|
}, 100);
|
|
6800
7066
|
}
|
|
6801
|
-
|
|
7067
|
+
const prevScrollPosition = this.scrollPosition$.getValue();
|
|
7068
|
+
if (this.direction === 'top-to-bottom') {
|
|
7069
|
+
if (scrollPosition === 'top') {
|
|
7070
|
+
scrollPosition = 'bottom';
|
|
7071
|
+
}
|
|
7072
|
+
else if (scrollPosition === 'bottom') {
|
|
7073
|
+
scrollPosition = 'top';
|
|
7074
|
+
}
|
|
7075
|
+
}
|
|
7076
|
+
if (prevScrollPosition !== scrollPosition && !this.isJumpingToMessage) {
|
|
7077
|
+
if (scrollPosition === 'top' || scrollPosition === 'bottom') {
|
|
7078
|
+
(_a = this.virtualizedList) === null || _a === void 0 ? void 0 : _a.virtualizedItems$.pipe(take(1)).subscribe((items) => {
|
|
7079
|
+
var _a, _b, _c, _d;
|
|
7080
|
+
this.messageIdToAnchorTo =
|
|
7081
|
+
scrollPosition === 'top'
|
|
7082
|
+
? (_a = items[0]) === null || _a === void 0 ? void 0 : _a.id
|
|
7083
|
+
: (_b = items[items.length - 1]) === null || _b === void 0 ? void 0 : _b.id;
|
|
7084
|
+
this.anchorMessageTopOffset = (_d = (_c = document
|
|
7085
|
+
.getElementById(this.messageIdToAnchorTo)) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect()) === null || _d === void 0 ? void 0 : _d.top;
|
|
7086
|
+
});
|
|
7087
|
+
}
|
|
6802
7088
|
this.ngZone.run(() => {
|
|
6803
|
-
|
|
6804
|
-
this.containerHeight = this.scrollContainer.nativeElement.scrollHeight;
|
|
6805
|
-
let direction;
|
|
6806
|
-
if (this.direction === 'top-to-bottom') {
|
|
6807
|
-
direction = scrollPosition === 'top' ? 'newer' : 'older';
|
|
6808
|
-
}
|
|
6809
|
-
else {
|
|
6810
|
-
direction = scrollPosition === 'top' ? 'older' : 'newer';
|
|
6811
|
-
}
|
|
6812
|
-
const result = this.mode === 'main'
|
|
6813
|
-
? this.channelService.loadMoreMessages(direction)
|
|
6814
|
-
: this.channelService.loadMoreThreadReplies(direction);
|
|
6815
|
-
if (result) {
|
|
6816
|
-
(_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `Displaying loading indicator`, { tags: `message list ${this.mode}` });
|
|
6817
|
-
this.isLoading = true;
|
|
6818
|
-
(_c = result.catch) === null || _c === void 0 ? void 0 : _c.call(result, () => {
|
|
6819
|
-
this.isLoading = false;
|
|
6820
|
-
});
|
|
6821
|
-
}
|
|
6822
|
-
this.cdRef.detectChanges();
|
|
7089
|
+
this.scrollPosition$.next(scrollPosition);
|
|
6823
7090
|
});
|
|
6824
7091
|
}
|
|
6825
|
-
this.prevScrollTop = this.scrollContainer.nativeElement.scrollTop;
|
|
6826
7092
|
}
|
|
6827
7093
|
jumpToFirstUnreadMessage() {
|
|
6828
7094
|
if (!this.lastReadMessageId) {
|
|
@@ -6865,9 +7131,19 @@ class MessageListComponent {
|
|
|
6865
7131
|
: this.emptyThreadMessageListTemplate;
|
|
6866
7132
|
}
|
|
6867
7133
|
preserveScrollbarPosition() {
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
7134
|
+
var _a;
|
|
7135
|
+
if (!this.messageIdToAnchorTo) {
|
|
7136
|
+
return;
|
|
7137
|
+
}
|
|
7138
|
+
const messageToAlignTo = document.getElementById(this.messageIdToAnchorTo);
|
|
7139
|
+
this.messageIdToAnchorTo = undefined;
|
|
7140
|
+
this.scrollContainer.nativeElement.scrollTop +=
|
|
7141
|
+
(((_a = messageToAlignTo === null || messageToAlignTo === void 0 ? void 0 : messageToAlignTo.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.top) || 0) -
|
|
7142
|
+
(this.anchorMessageTopOffset || 0);
|
|
7143
|
+
this.anchorMessageTopOffset = undefined;
|
|
7144
|
+
if (this.isSafari) {
|
|
7145
|
+
this.forceRepaintSubject.next();
|
|
7146
|
+
}
|
|
6871
7147
|
}
|
|
6872
7148
|
forceRepaint() {
|
|
6873
7149
|
// Solves the issue of empty screen on Safari when scrolling
|
|
@@ -6876,13 +7152,10 @@ class MessageListComponent {
|
|
|
6876
7152
|
this.scrollContainer.nativeElement.style.display = '';
|
|
6877
7153
|
}
|
|
6878
7154
|
getScrollPosition() {
|
|
6879
|
-
var _a
|
|
7155
|
+
var _a;
|
|
6880
7156
|
let position = 'middle';
|
|
6881
7157
|
if (Math.floor(this.scrollContainer.nativeElement.scrollTop) <=
|
|
6882
|
-
(((_a = this.parentMessageElement) === null || _a === void 0 ? void 0 : _a.nativeElement.clientHeight) || 0)
|
|
6883
|
-
(this.prevScrollTop === undefined ||
|
|
6884
|
-
this.prevScrollTop >
|
|
6885
|
-
(((_b = this.parentMessageElement) === null || _b === void 0 ? void 0 : _b.nativeElement.clientHeight) || 0))) {
|
|
7158
|
+
(((_a = this.parentMessageElement) === null || _a === void 0 ? void 0 : _a.nativeElement.clientHeight) || 0)) {
|
|
6886
7159
|
position = 'top';
|
|
6887
7160
|
}
|
|
6888
7161
|
else if (Math.ceil(this.scrollContainer.nativeElement.scrollTop) +
|
|
@@ -6893,24 +7166,24 @@ class MessageListComponent {
|
|
|
6893
7166
|
}
|
|
6894
7167
|
return position;
|
|
6895
7168
|
}
|
|
6896
|
-
shouldLoadMoreMessages(scrollPosition) {
|
|
6897
|
-
return (scrollPosition !== 'middle' &&
|
|
6898
|
-
!this.highlightedMessageId &&
|
|
6899
|
-
!this.isLoading);
|
|
6900
|
-
}
|
|
6901
7169
|
setMessages$() {
|
|
6902
7170
|
var _a;
|
|
6903
|
-
this.
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
if (
|
|
6908
|
-
|
|
7171
|
+
this.disposeVirtualizedList();
|
|
7172
|
+
this.virtualizedList = new VirtualizedMessageListService(this.mode, this.scrollPosition$, this.channelService);
|
|
7173
|
+
this.queryStateSubscription = this.virtualizedList.queryState$.subscribe((queryState) => {
|
|
7174
|
+
let mappedState = 'idle';
|
|
7175
|
+
if (queryState.state.includes('loading')) {
|
|
7176
|
+
mappedState = queryState.state || 'loading-bottom';
|
|
7177
|
+
}
|
|
7178
|
+
if (mappedState !== this.loadingState) {
|
|
7179
|
+
this.loadingState = mappedState;
|
|
7180
|
+
if (this.isViewInited) {
|
|
7181
|
+
this.cdRef.detectChanges();
|
|
7182
|
+
}
|
|
6909
7183
|
}
|
|
7184
|
+
});
|
|
7185
|
+
this.messages$ = this.virtualizedList.virtualizedItems$.pipe(tap((messages) => {
|
|
6910
7186
|
if (messages.length === 0) {
|
|
6911
|
-
(_b = (_a = this.chatClientService.chatClient) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.call(_a, 'info', `Empty messages array, reseting scroll state`, {
|
|
6912
|
-
tags: `message list ${this.mode}`,
|
|
6913
|
-
});
|
|
6914
7187
|
this.resetScrollState();
|
|
6915
7188
|
return;
|
|
6916
7189
|
}
|
|
@@ -6918,21 +7191,6 @@ class MessageListComponent {
|
|
|
6918
7191
|
// cdRef.detectChanges() isn't enough here, test will fail
|
|
6919
7192
|
setTimeout(() => (this.isEmpty = false), 0);
|
|
6920
7193
|
}
|
|
6921
|
-
(_d = (_c = this.chatClientService.chatClient) === null || _c === void 0 ? void 0 : _c.logger) === null || _d === void 0 ? void 0 : _d.call(_c, 'info', `Received one or more messages`, {
|
|
6922
|
-
tags: `message list ${this.mode}`,
|
|
6923
|
-
});
|
|
6924
|
-
const currentLatestMessageInState = messages[messages.length - 1];
|
|
6925
|
-
this.newMessageReceived(currentLatestMessageInState);
|
|
6926
|
-
const currentOldestMessage = messages[0];
|
|
6927
|
-
if (!this.oldestMessage ||
|
|
6928
|
-
!messages.find((m) => m.id === this.oldestMessage.id)) {
|
|
6929
|
-
this.oldestMessage = currentOldestMessage;
|
|
6930
|
-
}
|
|
6931
|
-
else if (this.oldestMessage.created_at.getTime() >
|
|
6932
|
-
currentOldestMessage.created_at.getTime()) {
|
|
6933
|
-
this.oldestMessage = currentOldestMessage;
|
|
6934
|
-
this.olderMassagesLoaded = true;
|
|
6935
|
-
}
|
|
6936
7194
|
}), tap((messages) => {
|
|
6937
7195
|
var _a;
|
|
6938
7196
|
if (this.isJumpingToLatestUnreadMessage &&
|
|
@@ -6952,82 +7210,101 @@ class MessageListComponent {
|
|
|
6952
7210
|
m.status !== 'sending';
|
|
6953
7211
|
})) === null || _a === void 0 ? void 0 : _a.id);
|
|
6954
7212
|
}), tap((messages) => {
|
|
7213
|
+
var _a, _b;
|
|
7214
|
+
const latestMessageInList = messages[messages.length - 1];
|
|
7215
|
+
const channel = this.channelService.activeChannel;
|
|
7216
|
+
const messagesFromState = (this.mode === 'main'
|
|
7217
|
+
? channel === null || channel === void 0 ? void 0 : channel.state.latestMessages
|
|
7218
|
+
: channel === null || channel === void 0 ? void 0 : channel.state.threads[((_a = this.parentMessage) === null || _a === void 0 ? void 0 : _a.id) || '']) || [];
|
|
6955
7219
|
this.isLatestMessageInList =
|
|
6956
|
-
!
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
7220
|
+
!latestMessageInList ||
|
|
7221
|
+
latestMessageInList.cid !== (channel === null || channel === void 0 ? void 0 : channel.cid) ||
|
|
7222
|
+
(latestMessageInList === null || latestMessageInList === void 0 ? void 0 : latestMessageInList.id) ===
|
|
7223
|
+
((_b = messagesFromState[messagesFromState.length - 1]) === null || _b === void 0 ? void 0 : _b.id);
|
|
6960
7224
|
if (!this.isLatestMessageInList) {
|
|
6961
7225
|
this.isUserScrolled = true;
|
|
6962
7226
|
}
|
|
6963
|
-
}), map((messages) =>
|
|
7227
|
+
}), map((messages) => {
|
|
7228
|
+
return this.direction === 'bottom-to-top'
|
|
7229
|
+
? messages
|
|
7230
|
+
: [...messages].reverse();
|
|
7231
|
+
}), tap((messages) => {
|
|
6964
7232
|
this.groupStyles = messages.map((m, i) => getGroupStyles(m, messages[i - 1], messages[i + 1], {
|
|
6965
7233
|
lastReadMessageId: this.lastReadMessageId,
|
|
6966
7234
|
}));
|
|
6967
7235
|
this.isNextMessageOnSeparateDate = messages.map((m, i) => this.checkIfOnSeparateDates(m, messages[i + 1]));
|
|
6968
7236
|
}), shareReplay(1));
|
|
6969
|
-
(_a = this.
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
this.
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
this.mode === 'main' &&
|
|
6991
|
-
messages.length >
|
|
6992
|
-
ChannelService.MAX_MESSAGE_COUNT_IN_MESSAGE_LIST * 0.5 &&
|
|
6993
|
-
!this.isUserScrolled &&
|
|
6994
|
-
!this.highlightedMessageId &&
|
|
6995
|
-
this.isLatestMessageInList) {
|
|
6996
|
-
this.channelService.removeOldMessageFromMessageList();
|
|
6997
|
-
}
|
|
6998
|
-
}, 1500);
|
|
7237
|
+
if ((_a = this.virtualizedList) === null || _a === void 0 ? void 0 : _a.jumpToItem$) {
|
|
7238
|
+
this.jumpToItemSubscription = this.virtualizedList.jumpToItem$
|
|
7239
|
+
.pipe(filter((jumpToMessage) => { var _a; return !!((_a = jumpToMessage.item) === null || _a === void 0 ? void 0 : _a.id); }))
|
|
7240
|
+
.subscribe((jumpToMessage) => {
|
|
7241
|
+
var _a;
|
|
7242
|
+
let messageId = (_a = jumpToMessage.item) === null || _a === void 0 ? void 0 : _a.id;
|
|
7243
|
+
if (messageId) {
|
|
7244
|
+
if (this.isJumpingToLatestUnreadMessage) {
|
|
7245
|
+
messageId = this.firstUnreadMessageId || messageId;
|
|
7246
|
+
}
|
|
7247
|
+
if (jumpToMessage.position !== 'bottom') {
|
|
7248
|
+
this.highlightedMessageId = messageId;
|
|
7249
|
+
}
|
|
7250
|
+
else if (this.direction === 'top-to-bottom') {
|
|
7251
|
+
jumpToMessage.position = 'top';
|
|
7252
|
+
}
|
|
7253
|
+
this.isJumpingToMessage = true;
|
|
7254
|
+
this.scrollMessageIntoView({
|
|
7255
|
+
messageId: this.firstUnreadMessageId || messageId,
|
|
7256
|
+
position: jumpToMessage.position || 'middle',
|
|
7257
|
+
});
|
|
6999
7258
|
}
|
|
7000
|
-
}
|
|
7001
|
-
}
|
|
7259
|
+
});
|
|
7260
|
+
}
|
|
7002
7261
|
}
|
|
7003
7262
|
resetScrollState() {
|
|
7004
7263
|
this.isEmpty = true;
|
|
7005
|
-
this.latestMessage = undefined;
|
|
7006
|
-
this.hasNewMessages = true;
|
|
7007
7264
|
this.isUserScrolled = false;
|
|
7008
|
-
this.
|
|
7009
|
-
this.
|
|
7010
|
-
this.oldestMessage = undefined;
|
|
7265
|
+
this.messageIdToAnchorTo = undefined;
|
|
7266
|
+
this.anchorMessageTopOffset = undefined;
|
|
7011
7267
|
this.newMessageCountWhileBeingScrolled = 0;
|
|
7012
|
-
this.
|
|
7013
|
-
this.isNewMessageSentByUser = undefined;
|
|
7268
|
+
this.isNewMessageSentByUser = false;
|
|
7014
7269
|
this.isLatestMessageInList = true;
|
|
7270
|
+
this.isJumpingToMessage = false;
|
|
7271
|
+
this.scrollPosition$.next('bottom');
|
|
7272
|
+
this.loadingState = 'idle';
|
|
7273
|
+
}
|
|
7274
|
+
disposeVirtualizedList() {
|
|
7275
|
+
var _a, _b, _c;
|
|
7276
|
+
(_a = this.virtualizedList) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
7277
|
+
(_b = this.jumpToItemSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
7278
|
+
(_c = this.queryStateSubscription) === null || _c === void 0 ? void 0 : _c.unsubscribe();
|
|
7015
7279
|
}
|
|
7016
7280
|
get usersTyping$() {
|
|
7017
7281
|
return this.mode === 'thread'
|
|
7018
7282
|
? this.usersTypingInThread$
|
|
7019
7283
|
: this.usersTypingInChannel$;
|
|
7020
7284
|
}
|
|
7021
|
-
scrollMessageIntoView(
|
|
7022
|
-
const element = document.getElementById(messageId);
|
|
7285
|
+
scrollMessageIntoView(options, withRetry = true) {
|
|
7286
|
+
const element = document.getElementById(options.messageId);
|
|
7023
7287
|
if (!element && withRetry) {
|
|
7024
7288
|
// If the message was newly inserted into activeChannelMessages$, the message will be rendered after the current change detection cycle -> wait for this cycle to complete
|
|
7025
|
-
setTimeout(() => this.scrollMessageIntoView(
|
|
7289
|
+
setTimeout(() => this.scrollMessageIntoView(options, false));
|
|
7026
7290
|
}
|
|
7027
7291
|
else if (element) {
|
|
7292
|
+
const blockMapping = {
|
|
7293
|
+
top: 'start',
|
|
7294
|
+
bottom: 'end',
|
|
7295
|
+
middle: 'center',
|
|
7296
|
+
};
|
|
7028
7297
|
element.scrollIntoView({
|
|
7029
|
-
block:
|
|
7298
|
+
block: blockMapping[options.position],
|
|
7030
7299
|
});
|
|
7300
|
+
if (options.position !== 'middle') {
|
|
7301
|
+
options.position === 'bottom'
|
|
7302
|
+
? this.scrollToBottom()
|
|
7303
|
+
: this.scrollToTop();
|
|
7304
|
+
}
|
|
7305
|
+
setTimeout(() => {
|
|
7306
|
+
this.isJumpingToMessage = false;
|
|
7307
|
+
}, 0);
|
|
7031
7308
|
setTimeout(() => {
|
|
7032
7309
|
this.highlightedMessageId = undefined;
|
|
7033
7310
|
this.firstUnreadMessageId = undefined;
|
|
@@ -7036,40 +7313,27 @@ class MessageListComponent {
|
|
|
7036
7313
|
}, 1000);
|
|
7037
7314
|
}
|
|
7038
7315
|
}
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7316
|
+
newMessageReceived(message) {
|
|
7317
|
+
var _a, _b, _c, _d;
|
|
7318
|
+
if ((this.mode === 'main' && message.parent_id) ||
|
|
7319
|
+
(this.mode === 'thread' && message.parent_id !== ((_a = this.parentMessage) === null || _a === void 0 ? void 0 : _a.id))) {
|
|
7320
|
+
return;
|
|
7044
7321
|
}
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7322
|
+
const isNewMessageSentByCurrentUser = ((_b = message.user) === null || _b === void 0 ? void 0 : _b.id) === ((_d = (_c = this.chatClientService.chatClient) === null || _c === void 0 ? void 0 : _c.user) === null || _d === void 0 ? void 0 : _d.id);
|
|
7323
|
+
let shouldDetectChanges = false;
|
|
7324
|
+
if (!this.isNewMessageSentByUser && isNewMessageSentByCurrentUser) {
|
|
7325
|
+
this.isNewMessageSentByUser = true;
|
|
7326
|
+
shouldDetectChanges = true;
|
|
7048
7327
|
}
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
if (!this.
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
((_d = latestMessages[latestMessages.length - 1]) === null || _d === void 0 ? void 0 : _d.id) !== this.latestMessage.id)) {
|
|
7059
|
-
(_f = (_e = this.chatClientService.chatClient) === null || _e === void 0 ? void 0 : _e.logger) === null || _f === void 0 ? void 0 : _f.call(_e, 'info', `Received new message`, { tags: `message list ${this.mode}` });
|
|
7060
|
-
const isNewChannel = !this.latestMessage;
|
|
7061
|
-
this.latestMessage = message;
|
|
7062
|
-
this.hasNewMessages = true;
|
|
7063
|
-
this.isNewMessageSentByUser =
|
|
7064
|
-
((_g = message.user) === null || _g === void 0 ? void 0 : _g.id) === ((_j = (_h = this.chatClientService.chatClient) === null || _h === void 0 ? void 0 : _h.user) === null || _j === void 0 ? void 0 : _j.id);
|
|
7065
|
-
if (this.isUserScrolled) {
|
|
7066
|
-
this.newMessageCountWhileBeingScrolled++;
|
|
7067
|
-
}
|
|
7068
|
-
if (!this.isNewMessageSentByUser &&
|
|
7069
|
-
this.unreadCount !== undefined &&
|
|
7070
|
-
!isNewChannel) {
|
|
7071
|
-
this.unreadCount++;
|
|
7072
|
-
}
|
|
7328
|
+
if (this.isUserScrolled) {
|
|
7329
|
+
this.newMessageCountWhileBeingScrolled++;
|
|
7330
|
+
shouldDetectChanges = true;
|
|
7331
|
+
}
|
|
7332
|
+
if (!this.isNewMessageSentByUser && this.unreadCount !== undefined) {
|
|
7333
|
+
this.unreadCount++;
|
|
7334
|
+
shouldDetectChanges = true;
|
|
7335
|
+
}
|
|
7336
|
+
if (shouldDetectChanges && this.isViewInited) {
|
|
7073
7337
|
this.cdRef.detectChanges();
|
|
7074
7338
|
}
|
|
7075
7339
|
}
|
|
@@ -7081,10 +7345,10 @@ class MessageListComponent {
|
|
|
7081
7345
|
}
|
|
7082
7346
|
}
|
|
7083
7347
|
MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: CustomTemplatesService }, { token: DateParserService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
7084
|
-
MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode", direction: "direction", hideJumpToLatestButtonDuringScroll: "hideJumpToLatestButtonDuringScroll", displayDateSeparator: "displayDateSeparator", displayUnreadSeparator: "displayUnreadSeparator", dateSeparatorTextPos: "dateSeparatorTextPos", openMessageListAt: "openMessageListAt", hideUnreadCountForNotificationAndIndicator: "hideUnreadCountForNotificationAndIndicator", displayLoadingIndicator: "displayLoadingIndicator", limitNumberOfMessagesInList: "limitNumberOfMessagesInList" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "parentMessageElement", first: true, predicate: ["parentMessageElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-scroll$=\"scroll$\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [scroll$]=\"scroll$\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n scroll$: scroll$\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode", "isHighlighted", "scroll$"] }, { kind: "component", type: LoadingIndicatorComponent, selector: "stream-loading-indicator" }, { kind: "component", type: IconComponent, selector: "stream-icon", inputs: ["icon"] }, { kind: "component", type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7348
|
+
MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: MessageListComponent, selector: "stream-message-list", inputs: { mode: "mode", direction: "direction", hideJumpToLatestButtonDuringScroll: "hideJumpToLatestButtonDuringScroll", displayDateSeparator: "displayDateSeparator", displayUnreadSeparator: "displayUnreadSeparator", dateSeparatorTextPos: "dateSeparatorTextPos", openMessageListAt: "openMessageListAt", hideUnreadCountForNotificationAndIndicator: "hideUnreadCountForNotificationAndIndicator", displayLoadingIndicator: "displayLoadingIndicator" }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "parentMessageElement", first: true, predicate: ["parentMessageElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n style=\"overscroll-behavior-y: none\"\n>\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator-placeholder\n *ngIf=\"\n ((loadingState === 'loading-top' && direction === 'bottom-to-top') ||\n (loadingState === 'loading-bottom' &&\n direction === 'top-to-bottom')) &&\n displayLoadingIndicator;\n else loadingIndicatorPlaceholder\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator-placeholder>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator-placeholder\n *ngIf=\"\n ((loadingState === 'loading-bottom' &&\n direction === 'bottom-to-top') ||\n (loadingState === 'loading-top' &&\n direction === 'top-to-bottom')) &&\n displayLoadingIndicator;\n else loadingIndicatorPlaceholder\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator-placeholder>\n <ng-template #loadingIndicatorPlaceholder>\n <div class=\"str-chat__loading-indicator-placeholder\"></div>\n </ng-template>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-scroll$=\"scroll$\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [scroll$]=\"scroll$\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n scroll$: scroll$\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "isLastSentMessage", "mode", "isHighlighted", "scroll$"] }, { kind: "component", type: IconComponent, selector: "stream-icon", inputs: ["icon"] }, { kind: "component", type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon"] }, { kind: "component", type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder" }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7085
7349
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MessageListComponent, decorators: [{
|
|
7086
7350
|
type: Component,
|
|
7087
|
-
args: [{ selector: 'stream-message-list', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div #scrollContainer data-testid=\"scroll-container\" class=\"str-chat__list\">\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'bottom-to-top' && displayLoadingIndicator\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator\n *ngIf=\"\n isLoading && direction === 'top-to-bottom' && displayLoadingIndicator\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-scroll$=\"scroll$\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [scroll$]=\"scroll$\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n scroll$: scroll$\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n" }]
|
|
7351
|
+
args: [{ selector: 'stream-message-list', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container\n *ngIf=\"\n lastReadMessageId &&\n isUnreadNotificationVisible &&\n openMessageListAt === 'last-message' &&\n displayUnreadSeparator\n \"\n>\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesNotificationTemplate ||\n defaultUnreadMessagesNotification;\n context: {\n unreadCount: unreadCount,\n onDismiss: messageNotificationDismissClicked,\n onJump: messageNotificationJumpClicked\n }\n \"\n ></ng-container>\n</ng-container>\n<ng-template\n #defaultUnreadMessagesNotification\n let-unreadCount=\"unreadCount\"\n let-onDismiss=\"onDismiss\"\n let-onJump=\"onJump\"\n>\n <div\n class=\"str-chat__unread-messages-notification\"\n data-testid=\"unread-messages-notification\"\n >\n <button\n data-testid=\"unread-messages-notification-jump-to-message\"\n (click)=\"onJump()\"\n >\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </button>\n <button\n data-testid=\"unread-messages-notification-dismiss\"\n (click)=\"onDismiss()\"\n >\n <stream-icon-placeholder icon=\"close\"></stream-icon-placeholder>\n </button>\n </div>\n</ng-template>\n<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n style=\"overscroll-behavior-y: none\"\n>\n <ng-container *ngIf=\"mode === 'main' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <div class=\"str-chat__reverse-infinite-scroll str-chat__message-list-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n *ngIf=\"mode === 'thread' && parentMessage\"\n #parentMessageElement\n data-testid=\"parent-message\"\n class=\"str-chat__parent-message-li\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: parentMessage, index: 'parent' }\n \"\n ></ng-container>\n <div data-testid=\"reply-count\" class=\"str-chat__thread-start\">\n {{parentMessage.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </div>\n </li>\n <ng-container *ngIf=\"mode === 'thread' && isEmpty && emptyListTemplate\">\n <ng-container *ngTemplateOutlet=\"emptyListTemplate\"></ng-container>\n </ng-container>\n <stream-loading-indicator-placeholder\n *ngIf=\"\n ((loadingState === 'loading-top' && direction === 'bottom-to-top') ||\n (loadingState === 'loading-bottom' &&\n direction === 'top-to-bottom')) &&\n displayLoadingIndicator;\n else loadingIndicatorPlaceholder\n \"\n data-testid=\"top-loading-indicator\"\n ></stream-loading-indicator-placeholder>\n <ng-container *ngIf=\"messages$ | async as messages\">\n <ng-container\n *ngFor=\"\n let message of messages;\n let i = index;\n let isFirst = first;\n let isLast = last;\n trackBy: trackByMessageId\n \"\n >\n <ng-container *ngIf=\"isFirst\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: message.created_at,\n parsedDate: parseDate(message.created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n <li\n tabindex=\"0\"\n data-testclass=\"message\"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n id=\"{{ message.id }}\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplateContainer;\n context: { message: message, index: i }\n \"\n ></ng-container>\n </li>\n <ng-container\n *ngIf=\"\n (lastReadMessageId === message?.id &&\n direction === 'bottom-to-top') ||\n (direction === 'top-to-bottom' &&\n lastReadMessageId === messages[i + 1]?.id)\n \"\n >\n <li\n *ngIf=\"displayUnreadSeparator\"\n id=\"stream-chat-new-message-indicator\"\n data-testid=\"new-messages-indicator\"\n class=\"str-chat__li str-chat__unread-messages-separator-wrapper\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n customnewMessagesIndicatorTemplate ||\n defaultNewMessagesIndicator;\n context: { unreadCount: unreadCount }\n \"\n ></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"isNextMessageOnSeparateDate[i]\">\n <ng-container\n *ngTemplateOutlet=\"\n dateSeparator;\n context: {\n date: messages[i + 1].created_at,\n parsedDate: parseDate(messages[i + 1].created_at)\n }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n </ng-container>\n <stream-loading-indicator-placeholder\n *ngIf=\"\n ((loadingState === 'loading-bottom' &&\n direction === 'bottom-to-top') ||\n (loadingState === 'loading-top' &&\n direction === 'top-to-bottom')) &&\n displayLoadingIndicator;\n else loadingIndicatorPlaceholder\n \"\n data-testid=\"bottom-loading-indicator\"\n ></stream-loading-indicator-placeholder>\n <ng-template #loadingIndicatorPlaceholder>\n <div class=\"str-chat__loading-indicator-placeholder\"></div>\n </ng-template>\n </ul>\n <ng-template #defaultTypingIndicator let-usersTyping$=\"usersTyping$\">\n <!-- eslint-disable-next-line @angular-eslint/template/no-any -->\n <ng-container *ngIf=\"$any(usersTyping$ | async) as users\">\n <div\n *ngIf=\"users.length > 0\"\n data-testid=\"typing-indicator\"\n class=\"str-chat__typing-indicator str-chat__typing-indicator--typing\"\n >\n <div class=\"str-chat__typing-indicator__dots\">\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n <span class=\"str-chat__typing-indicator__dot\"></span>\n </div>\n <div\n data-testid=\"typing-users\"\n class=\"str-chat__typing-indicator__users\"\n >\n {{\n users.length === 1\n ? (\"streamChat.user is typing\"\n | translate: { user: getTypingIndicatorText(users) })\n : (\"streamChat.users are typing\"\n | translate: { users: getTypingIndicatorText(users) })\n }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n typingIndicatorTemplate || defaultTypingIndicator;\n context: getTypingIndicatorContext()\n \"\n ></ng-container>\n </div>\n</div>\n<div class=\"str-chat__jump-to-latest-message\">\n <button\n *ngIf=\"isUserScrolled && isJumpToLatestButtonVisible\"\n data-testid=\"scroll-to-latest\"\n class=\"\n str-chat__message-notification-scroll-to-latest\n str-chat__message-notification-scroll-to-latest-right\n str-chat__circle-fab\n \"\n (keyup.enter)=\"jumpToLatestMessage()\"\n (click)=\"jumpToLatestMessage()\"\n >\n <stream-icon\n class=\"str-chat__jump-to-latest-icon str-chat__circle-fab-icon\"\n [icon]=\"direction === 'bottom-to-top' ? 'arrow-down' : 'arrow-up'\"\n ></stream-icon>\n <div\n *ngIf=\"newMessageCountWhileBeingScrolled > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-to-latest-unread-count\n str-chat__jump-to-latest-unread-count\n \"\n >\n {{ newMessageCountWhileBeingScrolled }}\n </div>\n </button>\n</div>\n\n<ng-template #messageTemplateContainer let-message=\"message\" let-index=\"index\">\n <ng-template\n #defaultMessageTemplate\n let-messageInput=\"message\"\n let-isLastSentMessage=\"isLastSentMessage\"\n let-enabledMessageActions=\"enabledMessageActions\"\n let-mode=\"mode\"\n let-isHighlighted=\"isHighlighted\"\n let-scroll$=\"scroll$\"\n >\n <stream-message\n [message]=\"messageInput\"\n [isLastSentMessage]=\"isLastSentMessage\"\n [enabledMessageActions]=\"enabledMessageActions\"\n [mode]=\"mode\"\n [isHighlighted]=\"isHighlighted\"\n [scroll$]=\"scroll$\"\n ></stream-message>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate || defaultMessageTemplate;\n context: {\n message: message,\n isLastSentMessage: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n enabledMessageActions: enabledMessageActions,\n mode: mode,\n isHighlighted: message?.id === highlightedMessageId,\n scroll$: scroll$\n }\n \"\n ></ng-container>\n</ng-template>\n\n<ng-template #dateSeparator let-date=\"date\" let-parsedDate=\"parsedDate\">\n <ng-container *ngIf=\"displayDateSeparator\">\n <ng-container\n *ngTemplateOutlet=\"\n customDateSeparatorTemplate || defaultDateSeparator;\n context: {\n date: date,\n parsedDate: parsedDate\n }\n \"\n ></ng-container>\n </ng-container>\n\n <ng-template\n #defaultDateSeparator\n let-date=\"date\"\n let-parsedDate=\"parsedDate\"\n >\n <div data-testid=\"date-separator\" class=\"str-chat__date-separator\">\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'right' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n <div class=\"str-chat__date-separator-date\">\n {{ parsedDate }}\n </div>\n <hr\n *ngIf=\"\n dateSeparatorTextPos === 'left' || dateSeparatorTextPos === 'center'\n \"\n class=\"str-chat__date-separator-line\"\n />\n </div>\n </ng-template>\n</ng-template>\n\n<ng-template #defaultNewMessagesIndicator let-unreadCount=\"unreadCount\">\n <div class=\"str-chat__unread-messages-separator\">\n <ng-container\n *ngIf=\"\n unreadCount > 0 && !hideUnreadCountForNotificationAndIndicator;\n else noUnreadCount\n \"\n >\n {{\n (unreadCount === 1\n ? \"streamChat.\\{\\{count\\}\\} unread message\"\n : \"streamChat.\\{\\{count\\}\\} unread messages\"\n ) | translate: { count: unreadCount }\n }}\n </ng-container>\n <ng-template #noUnreadCount>\n {{ \"streamChat.Unread messages\" | translate }}\n </ng-template>\n </div>\n</ng-template>\n" }]
|
|
7088
7352
|
}], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: CustomTemplatesService }, { type: DateParserService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { mode: [{
|
|
7089
7353
|
type: Input
|
|
7090
7354
|
}], direction: [{
|
|
@@ -7103,8 +7367,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
|
|
|
7103
7367
|
type: Input
|
|
7104
7368
|
}], displayLoadingIndicator: [{
|
|
7105
7369
|
type: Input
|
|
7106
|
-
}], limitNumberOfMessagesInList: [{
|
|
7107
|
-
type: Input
|
|
7108
7370
|
}], scrollContainer: [{
|
|
7109
7371
|
type: ViewChild,
|
|
7110
7372
|
args: ['scrollContainer']
|
|
@@ -7351,5 +7613,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
|
|
|
7351
7613
|
* Generated bundle index. Do not edit.
|
|
7352
7614
|
*/
|
|
7353
7615
|
|
|
7354
|
-
export { AttachmentConfigurationService, AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, AvatarPlaceholderComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelPreviewComponent, ChannelQuery, ChannelService, ChatClientService, CustomTemplatesService, DateParserService, EmojiInputService, IconComponent, IconPlaceholderComponent, LoadingIndicatorComponent, LoadingIndicatorPlaceholderComponent, MessageActionsBoxComponent, MessageActionsService, MessageBouncePromptComponent, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, MessageReactionsSelectorComponent, MessageReactionsService, MessageService, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, VoiceRecordingComponent, VoiceRecordingWavebarComponent, createMessagePreview, getChannelDisplayText, getGroupStyles, getMessageTranslation, getReadBy, isImageAttachment, isImageFile, isOnSeparateDate, listUsers, parseDate, textareaInjectionToken };
|
|
7616
|
+
export { AttachmentConfigurationService, AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, AvatarPlaceholderComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelPreviewComponent, ChannelQuery, ChannelService, ChatClientService, CustomTemplatesService, DateParserService, EmojiInputService, IconComponent, IconPlaceholderComponent, LoadingIndicatorComponent, LoadingIndicatorPlaceholderComponent, MessageActionsBoxComponent, MessageActionsService, MessageBouncePromptComponent, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, MessageReactionsSelectorComponent, MessageReactionsService, MessageService, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, VirtualizedListService, VirtualizedMessageListService, VoiceRecordingComponent, VoiceRecordingWavebarComponent, createMessagePreview, getChannelDisplayText, getGroupStyles, getMessageTranslation, getReadBy, isImageAttachment, isImageFile, isOnSeparateDate, listUsers, parseDate, textareaInjectionToken };
|
|
7355
7617
|
//# sourceMappingURL=stream-chat-angular.mjs.map
|