stream-chat-angular 2.1.0 → 2.2.0

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.
@@ -16,7 +16,7 @@ import transliterate from '@stream-io/transliterate';
16
16
  import * as i5 from 'angular-mentions';
17
17
  import { MentionModule } from 'angular-mentions';
18
18
 
19
- const version = '2.1.0';
19
+ const version = '2.2.0';
20
20
 
21
21
  class NotificationService {
22
22
  constructor() {
@@ -218,7 +218,9 @@ class ChannelService {
218
218
  channel.state.messages.forEach((m) => {
219
219
  m.readBy = getReadBy(m, channel);
220
220
  });
221
- void channel.markRead();
221
+ if (this.canSendReadEvents) {
222
+ void channel.markRead();
223
+ }
222
224
  this.activeChannelMessagesSubject.next([...channel.state.messages]);
223
225
  }
224
226
  loadMoreMessages() {
@@ -457,9 +459,11 @@ class ChannelService {
457
459
  this.activeChannelSubscriptions.push(channel.on('message.new', () => {
458
460
  this.ngZone.run(() => {
459
461
  this.activeChannelMessagesSubject.next([...channel.state.messages]);
460
- this.activeChannel$
461
- .pipe(first())
462
- .subscribe((c) => void (c === null || c === void 0 ? void 0 : c.markRead()));
462
+ this.activeChannel$.pipe(first()).subscribe((c) => {
463
+ if (this.canSendReadEvents) {
464
+ void (c === null || c === void 0 ? void 0 : c.markRead());
465
+ }
466
+ });
463
467
  });
464
468
  }));
465
469
  this.activeChannelSubscriptions.push(channel.on('message.updated', (event) => this.messageUpdated(event)));
@@ -658,6 +662,15 @@ class ChannelService {
658
662
  get channels() {
659
663
  return this.channelsSubject.getValue() || [];
660
664
  }
665
+ get canSendReadEvents() {
666
+ var _a;
667
+ const channel = this.activeChannelSubject.getValue();
668
+ if (!channel) {
669
+ return false;
670
+ }
671
+ const capabilites = (_a = channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
672
+ return capabilites.indexOf('read-events') !== -1;
673
+ }
661
674
  }
662
675
  ChannelService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0.ApplicationRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
663
676
  ChannelService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, providedIn: 'root' });
@@ -1014,6 +1027,8 @@ const en = {
1014
1027
  failed: 'failed',
1015
1028
  retry: 'retry',
1016
1029
  test: 'success',
1030
+ 'Sending links is not allowed in this conversation': 'Sending links is not allowed in this conversation',
1031
+ "You can't send messages in this channel": "You can't send messages in this channel",
1017
1032
  },
1018
1033
  };
1019
1034
 
@@ -1220,27 +1235,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1220
1235
  }], ctorParameters: function () { return [{ type: AttachmentService }]; } });
1221
1236
 
1222
1237
  class MessageInputComponent {
1223
- constructor(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver) {
1238
+ constructor(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef) {
1224
1239
  this.channelService = channelService;
1225
1240
  this.notificationService = notificationService;
1226
1241
  this.attachmentService = attachmentService;
1227
1242
  this.configService = configService;
1228
1243
  this.textareaType = textareaType;
1229
1244
  this.componentFactoryResolver = componentFactoryResolver;
1245
+ this.cdRef = cdRef;
1230
1246
  this.messageUpdate = new EventEmitter();
1231
1247
  this.textareaValue = '';
1232
1248
  this.mentionedUsers = [];
1233
1249
  this.subscriptions = [];
1234
- this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
1235
- var _a;
1236
- this.textareaValue = '';
1237
- this.attachmentService.resetAttachmentUploads();
1238
- const capabilities = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
1239
- if (capabilities) {
1240
- this.isFileUploadAuthorized =
1241
- capabilities.indexOf('upload-file') !== -1;
1242
- }
1243
- }));
1244
1250
  this.subscriptions.push(this.attachmentService.attachmentUploadInProgressCounter$.subscribe((counter) => {
1245
1251
  if (counter === 0 && this.hideNotification) {
1246
1252
  this.hideNotification();
@@ -1258,9 +1264,23 @@ class MessageInputComponent {
1258
1264
  this.mentionScope = this.configService.mentionScope;
1259
1265
  }
1260
1266
  ngOnInit() {
1261
- const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.textareaType);
1262
- this.textareaRef =
1263
- this.textareaAnchor.viewContainerRef.createComponent(componentFactory);
1267
+ this.subscriptions.push(this.channelService.activeChannel$.subscribe((channel) => {
1268
+ var _a;
1269
+ this.textareaValue = '';
1270
+ this.attachmentService.resetAttachmentUploads();
1271
+ const capabilities = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
1272
+ if (capabilities) {
1273
+ this.isFileUploadAuthorized =
1274
+ capabilities.indexOf('upload-file') !== -1;
1275
+ this.canSendLinks = capabilities.indexOf('send-links') !== -1;
1276
+ this.canSendMessages = capabilities.indexOf('send-message') !== -1;
1277
+ this.cdRef.detectChanges();
1278
+ this.initTextarea();
1279
+ }
1280
+ }));
1281
+ }
1282
+ ngAfterViewInit() {
1283
+ this.initTextarea();
1264
1284
  }
1265
1285
  ngOnChanges(changes) {
1266
1286
  if (changes.message) {
@@ -1312,6 +1332,10 @@ class MessageInputComponent {
1312
1332
  if (!text && (!attachments || attachments.length === 0)) {
1313
1333
  return;
1314
1334
  }
1335
+ if (this.containsLinks && !this.canSendLinks) {
1336
+ this.notificationService.addTemporaryNotification('streamChat.Sending links is not allowed in this conversation');
1337
+ return;
1338
+ }
1315
1339
  if (!this.isUpdate) {
1316
1340
  this.textareaValue = '';
1317
1341
  }
@@ -1331,6 +1355,9 @@ class MessageInputComponent {
1331
1355
  }
1332
1356
  });
1333
1357
  }
1358
+ get containsLinks() {
1359
+ return /(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-&?=%.]+/.test(this.textareaValue);
1360
+ }
1334
1361
  get accept() {
1335
1362
  var _a;
1336
1363
  return this.acceptedFileTypes ? (_a = this.acceptedFileTypes) === null || _a === void 0 ? void 0 : _a.join(',') : '';
@@ -1347,9 +1374,18 @@ class MessageInputComponent {
1347
1374
  get isUpdate() {
1348
1375
  return !!this.message;
1349
1376
  }
1377
+ initTextarea() {
1378
+ if (!this.canSendMessages || this.textareaRef || !this.textareaAnchor) {
1379
+ return;
1380
+ }
1381
+ const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.textareaType);
1382
+ this.textareaRef =
1383
+ this.textareaAnchor.viewContainerRef.createComponent(componentFactory);
1384
+ this.cdRef.detectChanges();
1385
+ }
1350
1386
  }
1351
- MessageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0.ComponentFactoryResolver }], target: i0.ɵɵFactoryTarget.Component });
1352
- MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"str-chat__input-flat\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n>\n <div class=\"str-chat__input-flat-wrapper\">\n <div class=\"str-chat__input-flat--textarea-wrapper\">\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea\">\n <ng-template\n streamTextarea\n [(value)]=\"textareaValue\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i3.AsyncPipe, "translate": i1.TranslatePipe } });
1387
+ MessageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0.ComponentFactoryResolver }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1388
+ MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"str-chat__input-flat\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n>\n <div class=\"str-chat__input-flat-wrapper\">\n <div class=\"str-chat__input-flat--textarea-wrapper\">\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea\">\n <ng-template\n *ngIf=\"canSendMessages; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"\n 'streamChat.You can\\'t send messages in this channel' | translate\n \"\n class=\"rta__textarea str-chat__textarea__textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i3.AsyncPipe, "translate": i1.TranslatePipe } });
1353
1389
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, decorators: [{
1354
1390
  type: Component,
1355
1391
  args: [{
@@ -1361,7 +1397,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1361
1397
  }], ctorParameters: function () { return [{ type: ChannelService }, { type: NotificationService }, { type: AttachmentService }, { type: MessageInputConfigService }, { type: i0.Type, decorators: [{
1362
1398
  type: Inject,
1363
1399
  args: [textareaInjectionToken]
1364
- }] }, { type: i0.ComponentFactoryResolver }]; }, propDecorators: { isFileUploadEnabled: [{
1400
+ }] }, { type: i0.ComponentFactoryResolver }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { isFileUploadEnabled: [{
1365
1401
  type: Input
1366
1402
  }], areMentionsEnabled: [{
1367
1403
  type: Input
@@ -1382,7 +1418,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1382
1418
  args: ['fileInput']
1383
1419
  }], textareaAnchor: [{
1384
1420
  type: ViewChild,
1385
- args: [TextareaDirective, { static: true }]
1421
+ args: [TextareaDirective, { static: false }]
1386
1422
  }] } });
1387
1423
 
1388
1424
  class ModalComponent {
@@ -1689,7 +1725,16 @@ class ChannelHeaderComponent {
1689
1725
  constructor(channelService, channelListToggleService) {
1690
1726
  this.channelService = channelService;
1691
1727
  this.channelListToggleService = channelListToggleService;
1692
- this.channelService.activeChannel$.subscribe((c) => (this.activeChannel = c));
1728
+ this.channelService.activeChannel$.subscribe((c) => {
1729
+ var _a, _b;
1730
+ this.activeChannel = c;
1731
+ const capabilities = (_b = (_a = this.activeChannel) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.own_capabilities;
1732
+ if (!capabilities) {
1733
+ return;
1734
+ }
1735
+ this.canReceiveConnectEvents =
1736
+ capabilities.indexOf('connect-events') !== -1;
1737
+ });
1693
1738
  }
1694
1739
  toggleMenu(event) {
1695
1740
  event.stopPropagation();
@@ -1705,7 +1750,7 @@ class ChannelHeaderComponent {
1705
1750
  }
1706
1751
  }
1707
1752
  ChannelHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0.ɵɵFactoryTarget.Component });
1708
- ChannelHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n </div>\n <stream-avatar\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar>\n <div class=\"str-chat__header-livestream-left\">\n <p class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{'streamChat.{{ watcherCount }} online' | translate:watcherCountParam}}\n </p>\n </div>\n</div>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i1.TranslatePipe } });
1753
+ ChannelHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n </div>\n <stream-avatar\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar>\n <div class=\"str-chat__header-livestream-left\">\n <p data-testid=\"name\" class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p data-testid=\"info\" class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{canReceiveConnectEvents ? ('streamChat.{{ watcherCount }} online' |\n translate:watcherCountParam) : ''}}\n </p>\n </div>\n</div>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i1.TranslatePipe } });
1709
1754
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelHeaderComponent, decorators: [{
1710
1755
  type: Component,
1711
1756
  args: [{
@@ -1722,20 +1767,24 @@ class ChannelPreviewComponent {
1722
1767
  this.isUnread = false;
1723
1768
  this.latestMessage = 'Nothing yet...';
1724
1769
  this.subscriptions = [];
1770
+ this.canSendReadEvents = true;
1725
1771
  }
1726
1772
  ngOnInit() {
1727
- var _a, _b;
1773
+ var _a, _b, _c, _d;
1728
1774
  this.subscriptions.push(this.channelService.activeChannel$.subscribe((activeChannel) => { var _a; return (this.isActive = (activeChannel === null || activeChannel === void 0 ? void 0 : activeChannel.id) === ((_a = this.channel) === null || _a === void 0 ? void 0 : _a.id)); }));
1729
1775
  const messages = (_b = (_a = this.channel) === null || _a === void 0 ? void 0 : _a.state) === null || _b === void 0 ? void 0 : _b.messages;
1730
1776
  if (messages && messages.length > 0) {
1731
1777
  this.setLatestMessage(messages[messages.length - 1]);
1732
1778
  }
1733
- this.isUnread = !!this.channel.countUnread();
1779
+ this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
1780
+ const capabilities = ((_d = (_c = this.channel) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.own_capabilities) || [];
1781
+ this.canSendReadEvents = capabilities.indexOf('read-events') !== -1;
1734
1782
  this.subscriptions.push(this.channel.on('message.new', this.handleMessageEvent.bind(this)));
1735
1783
  this.subscriptions.push(this.channel.on('message.updated', this.handleMessageEvent.bind(this)));
1736
1784
  this.subscriptions.push(this.channel.on('message.deleted', this.handleMessageEvent.bind(this)));
1737
1785
  this.subscriptions.push(this.channel.on('channel.truncated', this.handleMessageEvent.bind(this)));
1738
- this.subscriptions.push(this.channel.on('message.read', () => (this.isUnread = !!this.channel.countUnread())));
1786
+ this.subscriptions.push(this.channel.on('message.read', () => (this.isUnread =
1787
+ !!this.channel.countUnread() && this.canSendReadEvents)));
1739
1788
  }
1740
1789
  ngOnDestroy() {
1741
1790
  this.subscriptions.forEach((s) => s.unsubscribe());
@@ -1766,7 +1815,7 @@ class ChannelPreviewComponent {
1766
1815
  return;
1767
1816
  }
1768
1817
  this.setLatestMessage(event.message);
1769
- this.isUnread = !!this.channel.countUnread();
1818
+ this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
1770
1819
  }
1771
1820
  setLatestMessage(message) {
1772
1821
  if (message === null || message === void 0 ? void 0 : message.deleted_at) {
@@ -2178,7 +2227,7 @@ class MessageComponent {
2178
2227
  }
2179
2228
  }
2180
2229
  MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
2181
- MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"\n areReactionsEnabled && hasReactions\n \"\n data-testid=\"message-container\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container *ngIf=\"isMessageDeliveredAndRead; else deliveredStatus\">\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <stream-message-actions-box\n [isOpen]=\"isActionBoxOpen\"\n [isMine]=\"isSentByCurrentUser\"\n [enabledActions]=\"enabledMessageActions\"\n [message]=\"message\"\n (displayedActionsCount)=\"visibleMessageActionsCount = $event\"\n (isEditing)=\"isEditing = $event; isActionBoxOpen = !isEditing\"\n ></stream-message-actions-box>\n <stream-icon\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon>\n </div>\n <div\n *ngIf=\"areReactionsEnabled && canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon icon=\"reaction-icon\"></stream-icon>\n </div>\n </div>\n <stream-message-reactions\n *ngIf=\"areReactionsEnabled\"\n [messageReactionCounts]=\"message?.reaction_counts || {}\"\n [latestReactions]=\"message?.latest_reactions || []\"\n [(isSelectorOpen)]=\"isReactionSelectorOpen\"\n [messageId]=\"message?.id\"\n [ownReactions]=\"message?.own_reactions || []\"\n ></stream-message-reactions>\n <stream-attachment-list\n *ngIf=\"hasAttachment\"\n [attachments]=\"message!.attachments!\"\n ></stream-attachment-list>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n [innerHTML]=\"\n message?.html || message?.text\n | highlightMentions: message?.mentioned_users\n \"\n ></div>\n </div>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"sending-indicator\">\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"read-indicator\">\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n class=\"str-chat__message-simple-status\"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["attachments"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1.TranslatePipe, "highlightMentions": HighlightMentionsPipe } });
2230
+ MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage", canReceiveReadEvents: "canReceiveReadEvents" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"\n areReactionsEnabled && hasReactions\n \"\n data-testid=\"message-container\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n isMessageDeliveredAndRead && canReceiveReadEvents;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <stream-message-actions-box\n [isOpen]=\"isActionBoxOpen\"\n [isMine]=\"isSentByCurrentUser\"\n [enabledActions]=\"enabledMessageActions\"\n [message]=\"message\"\n (displayedActionsCount)=\"visibleMessageActionsCount = $event\"\n (isEditing)=\"isEditing = $event; isActionBoxOpen = !isEditing\"\n ></stream-message-actions-box>\n <stream-icon\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon>\n </div>\n <div\n *ngIf=\"areReactionsEnabled && canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon icon=\"reaction-icon\"></stream-icon>\n </div>\n </div>\n <stream-message-reactions\n *ngIf=\"areReactionsEnabled\"\n [messageReactionCounts]=\"message?.reaction_counts || {}\"\n [latestReactions]=\"message?.latest_reactions || []\"\n [(isSelectorOpen)]=\"isReactionSelectorOpen\"\n [messageId]=\"message?.id\"\n [ownReactions]=\"message?.own_reactions || []\"\n ></stream-message-reactions>\n <stream-attachment-list\n *ngIf=\"hasAttachment\"\n [attachments]=\"message!.attachments!\"\n ></stream-attachment-list>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n [innerHTML]=\"\n message?.html || message?.text\n | highlightMentions: message?.mentioned_users\n \"\n ></div>\n </div>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"sending-indicator\">\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"read-indicator\">\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n class=\"str-chat__message-simple-status\"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["attachments"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1.TranslatePipe, "highlightMentions": HighlightMentionsPipe } });
2182
2231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, decorators: [{
2183
2232
  type: Component,
2184
2233
  args: [{
@@ -2196,6 +2245,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
2196
2245
  type: Input
2197
2246
  }], isLastSentMessage: [{
2198
2247
  type: Input
2248
+ }], canReceiveReadEvents: [{
2249
+ type: Input
2199
2250
  }], container: [{
2200
2251
  type: ViewChild,
2201
2252
  args: ['container']
@@ -2463,6 +2514,7 @@ class MessageListComponent {
2463
2514
  const capabilites = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
2464
2515
  if (capabilites) {
2465
2516
  this.canReactToMessage = capabilites.indexOf('send-reaction') !== -1;
2517
+ this.canReceiveReadEvents = capabilites.indexOf('read-events') !== -1;
2466
2518
  this.authorizedMessageActions = [];
2467
2519
  if (capabilites.indexOf('flag-message') !== -1) {
2468
2520
  this.authorizedMessageActions.push('flag');
@@ -2593,7 +2645,7 @@ class MessageListComponent {
2593
2645
  }
2594
2646
  }
2595
2647
  MessageListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }], target: i0.ɵɵFactoryTarget.Component });
2596
- MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { messageTemplate: "messageTemplate", areReactionsEnabled: "areReactionsEnabled", enabledMessageActionsInput: ["enabledMessageActions", "enabledMessageActionsInput"] }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container *ngIf=\"messageTemplate; else defaultMessageTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate;\n context: {\n message: message,\n areReactionsEnabled: areReactionsEnabled,\n canReactToMessage: canReactToMessage,\n lastSentMessageId: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n )\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMessageTemplate>\n <stream-message\n [message]=\"message\"\n [areReactionsEnabled]=\"areReactionsEnabled\"\n [canReactToMessage]=\"canReactToMessage\"\n [isLastSentMessage]=\"\n !!(lastSentMessageId && message?.id === lastSentMessageId)\n \"\n [enabledMessageActions]=\"enabledMessageActions\"\n ></stream-message>\n </ng-template>\n </li>\n </ul>\n </div>\n</div>\n<div class=\"str-chat__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n", components: [{ type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "areReactionsEnabled", "canReactToMessage", "isLastSentMessage"] }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe } });
2648
+ MessageListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { messageTemplate: "messageTemplate", areReactionsEnabled: "areReactionsEnabled", enabledMessageActionsInput: ["enabledMessageActions", "enabledMessageActionsInput"] }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container *ngIf=\"messageTemplate; else defaultMessageTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate;\n context: {\n message: message,\n areReactionsEnabled: areReactionsEnabled,\n canReactToMessage: canReactToMessage,\n lastSentMessageId: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n canReceiveReadEvents: canReceiveReadEvents\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMessageTemplate>\n <stream-message\n [message]=\"message\"\n [areReactionsEnabled]=\"areReactionsEnabled\"\n [canReactToMessage]=\"canReactToMessage\"\n [isLastSentMessage]=\"\n !!(lastSentMessageId && message?.id === lastSentMessageId)\n \"\n [enabledMessageActions]=\"enabledMessageActions\"\n [canReceiveReadEvents]=\"canReceiveReadEvents\"\n ></stream-message>\n </ng-template>\n </li>\n </ul>\n </div>\n</div>\n<div class=\"str-chat__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n", components: [{ type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "areReactionsEnabled", "canReactToMessage", "isLastSentMessage", "canReceiveReadEvents"] }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3.AsyncPipe } });
2597
2649
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageListComponent, decorators: [{
2598
2650
  type: Component,
2599
2651
  args: [{