From cf6ae8761ed532e9bd5a5a4dff1dabbbbf443c2c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 22 Feb 2021 17:39:23 +0530 Subject: [PATCH 1/8] [Persistence] Add support for pinned messages Signed-off-by: Sahil Kumar --- .../lib/src/db/chat_persistence_client.dart | 39 + .../lib/src/dao/channel_query_dao.dart | 2 + .../lib/src/dao/dao.dart | 1 + .../lib/src/dao/message_dao.dart | 24 +- .../lib/src/dao/pinned_message_dao.dart | 169 ++ .../lib/src/dao/pinned_message_dao.g.dart | 12 + .../lib/src/db/moor_chat_database.dart | 4 +- .../lib/src/db/moor_chat_database.g.dart | 1375 ++++++++++++++++- .../lib/src/entity/entity.dart | 1 + .../lib/src/entity/messages.dart | 12 + .../lib/src/entity/pinned_messages.dart | 7 + .../lib/src/mapper/channel_mapper.dart | 2 + .../lib/src/mapper/mapper.dart | 1 + .../lib/src/mapper/message_mapper.dart | 9 + .../lib/src/mapper/pinned_message_mapper.dart | 81 + .../src/stream_chat_persistence_client.dart | 26 + packages/stream_chat_persistence/pubspec.yaml | 3 +- 17 files changed, 1759 insertions(+), 9 deletions(-) create mode 100644 packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index ac65783d..9c31eca9 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -56,10 +56,17 @@ abstract class ChatPersistenceClient { PaginationParams messagePagination, }); + /// Get stored pinned [Message]s by providing channel [cid] + Future> getPinnedMessagesByCid( + String cid, { + PaginationParams messagePagination, + }); + /// Get [ChannelState] data by providing channel [cid] Future getChannelStateByCid( String cid, { PaginationParams messagePagination, + PaginationParams pinnedMessagePagination, }) async { final members = await getMembersByCid(cid); final reads = await getReadsByCid(cid); @@ -68,10 +75,15 @@ abstract class ChatPersistenceClient { cid, messagePagination: messagePagination, ); + final pinnedMessages = await getPinnedMessagesByCid( + cid, + messagePagination: pinnedMessagePagination, + ); return ChannelState( members: members, read: reads, messages: messages, + pinnedMessages: pinnedMessages, channel: channel, ); } @@ -101,17 +113,33 @@ abstract class ChatPersistenceClient { return deleteMessageByIds([messageId]); } + /// Remove a pinned message by [messageId] + Future deletePinnedMessageById(String messageId) { + return deletePinnedMessageByIds([messageId]); + } + /// Remove a message by [messageIds] Future deleteMessageByIds(List messageIds); + /// Remove a pinned message by [messageIds] + Future deletePinnedMessageByIds(List messageIds); + /// Remove a message by channel [cid] Future deleteMessageByCid(String cid) { return deleteMessageByCids([cid]); } + /// Remove a pinned message by channel [cid] + Future deletePinnedMessageByCid(String cid) { + return deletePinnedMessageByCids([cid]); + } + /// Remove a message by message [cids] Future deleteMessageByCids(List cids); + /// Remove a pinned message by message [cids] + Future deletePinnedMessageByCids(List cids); + /// Remove a channel by [cid] Future deleteChannels(List cids); @@ -119,6 +147,10 @@ abstract class ChatPersistenceClient { /// the new [messages] data Future updateMessages(String cid, List messages); + /// Updates the pinned message data of a particular channel [cid] with + /// the new [messages] data + Future updatePinnedMessages(String cid, List messages); + /// Returns all the threads by parent message of a particular channel by /// providing channel [cid] Future>> getChannelThreads(String cid); @@ -204,6 +236,12 @@ abstract class ChatPersistenceClient { return updateMessages(cid, messages.toList(growable: false)); }).toList(growable: false); + final updatePinnedMessagesFuture = channelStates.map((it) { + final cid = it.channel.cid; + final messages = it.pinnedMessages.where((it) => it != null); + return updatePinnedMessages(cid, messages.toList(growable: false)); + }).toList(growable: false); + final updateReadsFuture = channelStates.map((it) { final cid = it.channel.cid; final reads = it.read?.where((it) => it != null) ?? []; @@ -218,6 +256,7 @@ abstract class ChatPersistenceClient { await Future.wait([ ...updateMessagesFuture, + ...updatePinnedMessagesFuture, ...updateReadsFuture, ...updateMembersFuture, updateUsers(users.toList(growable: false)), diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart index 1492420c..83743deb 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -101,12 +101,14 @@ class ChannelQueryDao extends DatabaseAccessor final members = await _db.memberDao.getMembersByCid(cid); final reads = await _db.readDao.getReadsByCid(cid); final messages = await _db.messageDao.getMessagesByCid(cid); + final pinnedMessages = await _db.pinnedMessageDao.getMessagesByCid(cid); return channelEntity.toChannelState( createdBy: userEntity?.toUser(), members: members, reads: reads, messages: messages, + pinnedMessages: pinnedMessages, ); }).get(); })); diff --git a/packages/stream_chat_persistence/lib/src/dao/dao.dart b/packages/stream_chat_persistence/lib/src/dao/dao.dart index 6f1e8221..31953630 100644 --- a/packages/stream_chat_persistence/lib/src/dao/dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/dao.dart @@ -1,6 +1,7 @@ export 'user_dao.dart'; export 'channel_dao.dart'; export 'message_dao.dart'; +export 'pinned_message_dao.dart'; export 'member_dao.dart'; export 'connection_event_dao.dart'; export 'reaction_dao.dart'; diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index c207ae20..01e5c889 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -17,6 +17,10 @@ class MessageDao extends DatabaseAccessor final MoorChatDatabase _db; + $UsersTable get _users => alias(users, 'users'); + + $UsersTable get _pinnedByUsers => alias(users, 'pinnedByUsers'); + /// Removes all the messages by matching [Messages.id] in [messageIds] /// /// This will automatically delete the following linked records @@ -34,7 +38,8 @@ class MessageDao extends DatabaseAccessor } Future _messageFromJoinRow(TypedResult rows) async { - final userEntity = rows.readTable(users); + final userEntity = rows.readTable(_users); + final pinnedByEntity = rows.readTable(_pinnedByUsers); final msgEntity = rows.readTable(messages); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); final ownReactions = await _db.reactionDao.getReactionsByUserId( @@ -47,6 +52,7 @@ class MessageDao extends DatabaseAccessor } return msgEntity.toMessage( user: userEntity?.toUser(), + pinnedBy: pinnedByEntity?.toUser(), latestReactions: latestReactions, ownReactions: ownReactions, quotedMessage: quotedMessage, @@ -56,7 +62,9 @@ class MessageDao extends DatabaseAccessor /// Returns a single message by matching the [Messages.id] with [id] Future getMessageById(String id) async { return await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), + leftOuterJoin( + _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) ..where(messages.id.equals(id))) .map(_messageFromJoinRow) @@ -67,7 +75,9 @@ class MessageDao extends DatabaseAccessor /// [Messages.channelCid] with [cid] Future> getThreadMessages(String cid) async { return Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), + leftOuterJoin(users, messages.userId.equalsExp(_users.id)), + leftOuterJoin( + _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) ..where(messages.channelCid.equals(cid)) ..where(isNotNull(messages.parentId)) @@ -83,7 +93,9 @@ class MessageDao extends DatabaseAccessor PaginationParams options, }) async { final msgList = await Future.wait(await (select(messages).join([ - innerJoin(users, messages.userId.equalsExp(users.id)), + innerJoin(_users, messages.userId.equalsExp(_users.id)), + innerJoin( + _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) ..where(messages.parentId.equals(parentId)) ..orderBy([OrderingTerm.asc(messages.createdAt)])) @@ -104,7 +116,9 @@ class MessageDao extends DatabaseAccessor PaginationParams messagePagination, }) async { final msgList = await Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), + leftOuterJoin( + _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) ..where(messages.channelCid.equals(cid)) ..where( diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart new file mode 100644 index 00000000..edf8e438 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -0,0 +1,169 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/pinned_messages.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; + +import '../mapper/mapper.dart'; + +part 'pinned_message_dao.g.dart'; + +/// The Data Access Object for operations in [Messages] table. +@UseDao(tables: [PinnedMessages, Users]) +class PinnedMessageDao extends DatabaseAccessor + with _$PinnedMessageDaoMixin { + /// Creates a new message dao instance + PinnedMessageDao(this._db) : super(_db); + + final MoorChatDatabase _db; + + $UsersTable get _users => alias(users, 'users'); + + $UsersTable get _pinnedByUsers => alias(users, 'pinnedByUsers'); + + /// Removes all the messages by matching [PinnedMessages.id] in [messageIds] + /// + /// This will automatically delete the following linked records + /// 1. Message Reactions + Future deleteMessageByIds(List messageIds) { + return (delete(pinnedMessages)..where((tbl) => tbl.id.isIn(messageIds))) + .go(); + } + + /// Removes all the messages by matching [PinnedMessages.channelCid] in [cids] + /// + /// This will automatically delete the following linked records + /// 1. Message Reactions + Future deleteMessageByCids(List cids) async { + return (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))) + .go(); + } + + Future _messageFromJoinRow(TypedResult rows) async { + final userEntity = rows.readTable(users); + final pinnedByEntity = rows.readTable(_pinnedByUsers); + final msgEntity = rows.readTable(pinnedMessages); + final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); + final ownReactions = await _db.reactionDao.getReactionsByUserId( + msgEntity.id, + _db.userId, + ); + Message quotedMessage; + if (msgEntity.quotedMessageId != null) { + quotedMessage = await getMessageById(msgEntity.quotedMessageId); + } + return msgEntity.toMessage( + user: userEntity?.toUser(), + pinnedBy: pinnedByEntity?.toUser(), + latestReactions: latestReactions, + ownReactions: ownReactions, + quotedMessage: quotedMessage, + ); + } + + /// Returns a single message by matching the [PinnedMessages.id] with [id] + Future getMessageById(String id) async { + return await (select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.id.equals(id))) + .map(_messageFromJoinRow) + .getSingle(); + } + + /// Returns all the messages of a particular thread by matching + /// [PinnedMessages.channelCid] with [cid] + Future> getThreadMessages(String cid) async { + return Future.wait(await (select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.channelCid.equals(cid)) + ..where(isNotNull(pinnedMessages.parentId)) + ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + } + + /// Returns all the messages of a particular thread by matching + /// [PinnedMessages.parentId] with [parentId] + Future> getThreadMessagesByParentId( + String parentId, { + PaginationParams options, + }) async { + final msgList = await Future.wait(await (select(pinnedMessages).join([ + innerJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + innerJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.parentId.equals(parentId)) + ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + + if (options?.lessThan != null) { + final lessThanIndex = msgList.indexWhere((m) => m.id == options.lessThan); + msgList.removeRange(lessThanIndex, msgList.length); + } + return msgList; + } + + /// Returns all the messages of a channel by matching + /// [PinnedMessages.channelCid] with [parentId] + Future> getMessagesByCid( + String cid, { + PaginationParams messagePagination, + }) async { + final msgList = await Future.wait(await (select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.channelCid.equals(cid)) + ..where(isNull(pinnedMessages.parentId) | + pinnedMessages.showInChannel.equals(true)) + ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + + if (messagePagination?.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.lessThan, + ); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } + } + if (messagePagination?.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.greaterThanOrEqual, + ); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (messagePagination?.limit != null) { + return msgList.take(messagePagination.limit).toList(); + } + return msgList; + } + + /// Updates the message data of a particular channel with + /// the new [messageList] data + Future updateMessages(String cid, List messageList) async { + if (messageList == null) { + return; + } + + return batch((batch) { + batch.insertAll( + pinnedMessages, + messageList.map((it) => it.toPinnedEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.g.dart new file mode 100644 index 00000000..e5e07850 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pinned_message_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$PinnedMessageDaoMixin on DatabaseAccessor { + $PinnedMessagesTable get pinnedMessages => attachedDatabase.pinnedMessages; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 4230f278..eae1abc6 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -25,6 +25,7 @@ LazyDatabase _openConnection( @UseMoor(tables: [ Channels, Messages, + PinnedMessages, Reactions, Users, Members, @@ -35,6 +36,7 @@ LazyDatabase _openConnection( UserDao, ChannelDao, MessageDao, + PinnedMessageDao, MemberDao, ReactionDao, ReadDao, @@ -67,7 +69,7 @@ class MoorChatDatabase extends _$MoorChatDatabase { // you should bump this number whenever you change or add a table definition. @override - int get schemaVersion => 1; + int get schemaVersion => 2; @override MigrationStrategy get migration => MigrationStrategy( diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart index 0ff6e9f5..b83b16da 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart @@ -673,6 +673,10 @@ class MessageEntity extends DataClass implements Insertable { final DateTime updatedAt; final DateTime deletedAt; final String userId; + final bool pinned; + final DateTime pinnedAt; + final DateTime pinExpires; + final String pinnedByUserId; final String channelCid; final Map extraData; MessageEntity( @@ -694,6 +698,10 @@ class MessageEntity extends DataClass implements Insertable { this.updatedAt, this.deletedAt, this.userId, + @required this.pinned, + this.pinnedAt, + this.pinExpires, + this.pinnedByUserId, this.channelCid, this.extraData}); factory MessageEntity.fromData( @@ -739,6 +747,14 @@ class MessageEntity extends DataClass implements Insertable { .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), userId: stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + pinned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}pinned']), + pinnedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}pinned_at']), + pinExpires: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}pin_expires']), + pinnedByUserId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}pinned_by_user_id']), channelCid: stringType .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), extraData: $MessagesTable.$converter5.mapToDart(stringType @@ -810,6 +826,18 @@ class MessageEntity extends DataClass implements Insertable { if (!nullToAbsent || userId != null) { map['user_id'] = Variable(userId); } + if (!nullToAbsent || pinned != null) { + map['pinned'] = Variable(pinned); + } + if (!nullToAbsent || pinnedAt != null) { + map['pinned_at'] = Variable(pinnedAt); + } + if (!nullToAbsent || pinExpires != null) { + map['pin_expires'] = Variable(pinExpires); + } + if (!nullToAbsent || pinnedByUserId != null) { + map['pinned_by_user_id'] = Variable(pinnedByUserId); + } if (!nullToAbsent || channelCid != null) { map['channel_cid'] = Variable(channelCid); } @@ -844,6 +872,10 @@ class MessageEntity extends DataClass implements Insertable { updatedAt: serializer.fromJson(json['updatedAt']), deletedAt: serializer.fromJson(json['deletedAt']), userId: serializer.fromJson(json['userId']), + pinned: serializer.fromJson(json['pinned']), + pinnedAt: serializer.fromJson(json['pinnedAt']), + pinExpires: serializer.fromJson(json['pinExpires']), + pinnedByUserId: serializer.fromJson(json['pinnedByUserId']), channelCid: serializer.fromJson(json['channelCid']), extraData: serializer.fromJson>(json['extraData']), ); @@ -870,6 +902,10 @@ class MessageEntity extends DataClass implements Insertable { 'updatedAt': serializer.toJson(updatedAt), 'deletedAt': serializer.toJson(deletedAt), 'userId': serializer.toJson(userId), + 'pinned': serializer.toJson(pinned), + 'pinnedAt': serializer.toJson(pinnedAt), + 'pinExpires': serializer.toJson(pinExpires), + 'pinnedByUserId': serializer.toJson(pinnedByUserId), 'channelCid': serializer.toJson(channelCid), 'extraData': serializer.toJson>(extraData), }; @@ -894,6 +930,10 @@ class MessageEntity extends DataClass implements Insertable { Value updatedAt = const Value.absent(), Value deletedAt = const Value.absent(), Value userId = const Value.absent(), + bool pinned, + Value pinnedAt = const Value.absent(), + Value pinExpires = const Value.absent(), + Value pinnedByUserId = const Value.absent(), Value channelCid = const Value.absent(), Value> extraData = const Value.absent()}) => MessageEntity( @@ -921,6 +961,11 @@ class MessageEntity extends DataClass implements Insertable { updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, userId: userId.present ? userId.value : this.userId, + pinned: pinned ?? this.pinned, + pinnedAt: pinnedAt.present ? pinnedAt.value : this.pinnedAt, + pinExpires: pinExpires.present ? pinExpires.value : this.pinExpires, + pinnedByUserId: + pinnedByUserId.present ? pinnedByUserId.value : this.pinnedByUserId, channelCid: channelCid.present ? channelCid.value : this.channelCid, extraData: extraData.present ? extraData.value : this.extraData, ); @@ -945,6 +990,10 @@ class MessageEntity extends DataClass implements Insertable { ..write('updatedAt: $updatedAt, ') ..write('deletedAt: $deletedAt, ') ..write('userId: $userId, ') + ..write('pinned: $pinned, ') + ..write('pinnedAt: $pinnedAt, ') + ..write('pinExpires: $pinExpires, ') + ..write('pinnedByUserId: $pinnedByUserId, ') ..write('channelCid: $channelCid, ') ..write('extraData: $extraData') ..write(')')) @@ -993,8 +1042,8 @@ class MessageEntity extends DataClass implements Insertable { userId .hashCode, $mrjc( - channelCid.hashCode, - extraData.hashCode)))))))))))))))))))); + pinned.hashCode, + $mrjc(pinnedAt.hashCode, $mrjc(pinExpires.hashCode, $mrjc(pinnedByUserId.hashCode, $mrjc(channelCid.hashCode, extraData.hashCode)))))))))))))))))))))))); @override bool operator ==(dynamic other) => identical(this, other) || @@ -1017,6 +1066,10 @@ class MessageEntity extends DataClass implements Insertable { other.updatedAt == this.updatedAt && other.deletedAt == this.deletedAt && other.userId == this.userId && + other.pinned == this.pinned && + other.pinnedAt == this.pinnedAt && + other.pinExpires == this.pinExpires && + other.pinnedByUserId == this.pinnedByUserId && other.channelCid == this.channelCid && other.extraData == this.extraData); } @@ -1040,6 +1093,10 @@ class MessagesCompanion extends UpdateCompanion { final Value updatedAt; final Value deletedAt; final Value userId; + final Value pinned; + final Value pinnedAt; + final Value pinExpires; + final Value pinnedByUserId; final Value channelCid; final Value> extraData; const MessagesCompanion({ @@ -1061,6 +1118,10 @@ class MessagesCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.deletedAt = const Value.absent(), this.userId = const Value.absent(), + this.pinned = const Value.absent(), + this.pinnedAt = const Value.absent(), + this.pinExpires = const Value.absent(), + this.pinnedByUserId = const Value.absent(), this.channelCid = const Value.absent(), this.extraData = const Value.absent(), }); @@ -1083,6 +1144,10 @@ class MessagesCompanion extends UpdateCompanion { this.updatedAt = const Value.absent(), this.deletedAt = const Value.absent(), this.userId = const Value.absent(), + this.pinned = const Value.absent(), + this.pinnedAt = const Value.absent(), + this.pinExpires = const Value.absent(), + this.pinnedByUserId = const Value.absent(), this.channelCid = const Value.absent(), this.extraData = const Value.absent(), }) : id = Value(id), @@ -1106,6 +1171,10 @@ class MessagesCompanion extends UpdateCompanion { Expression updatedAt, Expression deletedAt, Expression userId, + Expression pinned, + Expression pinnedAt, + Expression pinExpires, + Expression pinnedByUserId, Expression channelCid, Expression extraData, }) { @@ -1128,6 +1197,10 @@ class MessagesCompanion extends UpdateCompanion { if (updatedAt != null) 'updated_at': updatedAt, if (deletedAt != null) 'deleted_at': deletedAt, if (userId != null) 'user_id': userId, + if (pinned != null) 'pinned': pinned, + if (pinnedAt != null) 'pinned_at': pinnedAt, + if (pinExpires != null) 'pin_expires': pinExpires, + if (pinnedByUserId != null) 'pinned_by_user_id': pinnedByUserId, if (channelCid != null) 'channel_cid': channelCid, if (extraData != null) 'extra_data': extraData, }); @@ -1152,6 +1225,10 @@ class MessagesCompanion extends UpdateCompanion { Value updatedAt, Value deletedAt, Value userId, + Value pinned, + Value pinnedAt, + Value pinExpires, + Value pinnedByUserId, Value channelCid, Value> extraData}) { return MessagesCompanion( @@ -1173,6 +1250,10 @@ class MessagesCompanion extends UpdateCompanion { updatedAt: updatedAt ?? this.updatedAt, deletedAt: deletedAt ?? this.deletedAt, userId: userId ?? this.userId, + pinned: pinned ?? this.pinned, + pinnedAt: pinnedAt ?? this.pinnedAt, + pinExpires: pinExpires ?? this.pinExpires, + pinnedByUserId: pinnedByUserId ?? this.pinnedByUserId, channelCid: channelCid ?? this.channelCid, extraData: extraData ?? this.extraData, ); @@ -1244,6 +1325,18 @@ class MessagesCompanion extends UpdateCompanion { if (userId.present) { map['user_id'] = Variable(userId.value); } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (pinnedAt.present) { + map['pinned_at'] = Variable(pinnedAt.value); + } + if (pinExpires.present) { + map['pin_expires'] = Variable(pinExpires.value); + } + if (pinnedByUserId.present) { + map['pinned_by_user_id'] = Variable(pinnedByUserId.value); + } if (channelCid.present) { map['channel_cid'] = Variable(channelCid.value); } @@ -1275,6 +1368,10 @@ class MessagesCompanion extends UpdateCompanion { ..write('updatedAt: $updatedAt, ') ..write('deletedAt: $deletedAt, ') ..write('userId: $userId, ') + ..write('pinned: $pinned, ') + ..write('pinnedAt: $pinnedAt, ') + ..write('pinExpires: $pinExpires, ') + ..write('pinnedByUserId: $pinnedByUserId, ') ..write('channelCid: $channelCid, ') ..write('extraData: $extraData') ..write(')')) @@ -1517,6 +1614,54 @@ class $MessagesTable extends Messages ); } + final VerificationMeta _pinnedMeta = const VerificationMeta('pinned'); + GeneratedBoolColumn _pinned; + @override + GeneratedBoolColumn get pinned => _pinned ??= _constructPinned(); + GeneratedBoolColumn _constructPinned() { + return GeneratedBoolColumn('pinned', $tableName, false, + defaultValue: const Constant(false)); + } + + final VerificationMeta _pinnedAtMeta = const VerificationMeta('pinnedAt'); + GeneratedDateTimeColumn _pinnedAt; + @override + GeneratedDateTimeColumn get pinnedAt => _pinnedAt ??= _constructPinnedAt(); + GeneratedDateTimeColumn _constructPinnedAt() { + return GeneratedDateTimeColumn( + 'pinned_at', + $tableName, + true, + ); + } + + final VerificationMeta _pinExpiresMeta = const VerificationMeta('pinExpires'); + GeneratedDateTimeColumn _pinExpires; + @override + GeneratedDateTimeColumn get pinExpires => + _pinExpires ??= _constructPinExpires(); + GeneratedDateTimeColumn _constructPinExpires() { + return GeneratedDateTimeColumn( + 'pin_expires', + $tableName, + true, + ); + } + + final VerificationMeta _pinnedByUserIdMeta = + const VerificationMeta('pinnedByUserId'); + GeneratedTextColumn _pinnedByUserId; + @override + GeneratedTextColumn get pinnedByUserId => + _pinnedByUserId ??= _constructPinnedByUserId(); + GeneratedTextColumn _constructPinnedByUserId() { + return GeneratedTextColumn( + 'pinned_by_user_id', + $tableName, + true, + ); + } + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); GeneratedTextColumn _channelCid; @override @@ -1559,6 +1704,10 @@ class $MessagesTable extends Messages updatedAt, deletedAt, userId, + pinned, + pinnedAt, + pinExpires, + pinnedByUserId, channelCid, extraData ]; @@ -1641,6 +1790,26 @@ class $MessagesTable extends Messages context.handle(_userIdMeta, userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); } + if (data.containsKey('pinned')) { + context.handle(_pinnedMeta, + pinned.isAcceptableOrUnknown(data['pinned'], _pinnedMeta)); + } + if (data.containsKey('pinned_at')) { + context.handle(_pinnedAtMeta, + pinnedAt.isAcceptableOrUnknown(data['pinned_at'], _pinnedAtMeta)); + } + if (data.containsKey('pin_expires')) { + context.handle( + _pinExpiresMeta, + pinExpires.isAcceptableOrUnknown( + data['pin_expires'], _pinExpiresMeta)); + } + if (data.containsKey('pinned_by_user_id')) { + context.handle( + _pinnedByUserIdMeta, + pinnedByUserId.isAcceptableOrUnknown( + data['pinned_by_user_id'], _pinnedByUserIdMeta)); + } if (data.containsKey('channel_cid')) { context.handle( _channelCidMeta, @@ -1678,6 +1847,1201 @@ class $MessagesTable extends Messages MapConverter(); } +class PinnedMessageEntity extends DataClass + implements Insertable { + final String id; + final String messageText; + final List attachments; + final MessageSendingStatus status; + final String type; + final List mentionedUsers; + final Map reactionCounts; + final Map reactionScores; + final String parentId; + final String quotedMessageId; + final int replyCount; + final bool showInChannel; + final bool shadowed; + final String command; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime deletedAt; + final String userId; + final bool pinned; + final DateTime pinnedAt; + final DateTime pinExpires; + final String pinnedByUserId; + final String channelCid; + final Map extraData; + PinnedMessageEntity( + {@required this.id, + this.messageText, + this.attachments, + this.status, + this.type, + this.mentionedUsers, + this.reactionCounts, + this.reactionScores, + this.parentId, + this.quotedMessageId, + this.replyCount, + this.showInChannel, + this.shadowed, + this.command, + @required this.createdAt, + this.updatedAt, + this.deletedAt, + this.userId, + @required this.pinned, + this.pinnedAt, + this.pinExpires, + this.pinnedByUserId, + this.channelCid, + this.extraData}); + factory PinnedMessageEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + return PinnedMessageEntity( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + messageText: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}message_text']), + attachments: $PinnedMessagesTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}attachments'])), + status: $PinnedMessagesTable.$converter1.mapToDart( + intType.mapFromDatabaseResponse(data['${effectivePrefix}status'])), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + mentionedUsers: $PinnedMessagesTable.$converter2.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}mentioned_users'])), + reactionCounts: $PinnedMessagesTable.$converter3.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_counts'])), + reactionScores: $PinnedMessagesTable.$converter4.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_scores'])), + parentId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}parent_id']), + quotedMessageId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}quoted_message_id']), + replyCount: intType + .mapFromDatabaseResponse(data['${effectivePrefix}reply_count']), + showInChannel: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}show_in_channel']), + shadowed: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}shadowed']), + command: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}command']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + deletedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + pinned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}pinned']), + pinnedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}pinned_at']), + pinExpires: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}pin_expires']), + pinnedByUserId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}pinned_by_user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + extraData: $PinnedMessagesTable.$converter5.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || messageText != null) { + map['message_text'] = Variable(messageText); + } + if (!nullToAbsent || attachments != null) { + final converter = $PinnedMessagesTable.$converter0; + map['attachments'] = Variable(converter.mapToSql(attachments)); + } + if (!nullToAbsent || status != null) { + final converter = $PinnedMessagesTable.$converter1; + map['status'] = Variable(converter.mapToSql(status)); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || mentionedUsers != null) { + final converter = $PinnedMessagesTable.$converter2; + map['mentioned_users'] = + Variable(converter.mapToSql(mentionedUsers)); + } + if (!nullToAbsent || reactionCounts != null) { + final converter = $PinnedMessagesTable.$converter3; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts)); + } + if (!nullToAbsent || reactionScores != null) { + final converter = $PinnedMessagesTable.$converter4; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores)); + } + if (!nullToAbsent || parentId != null) { + map['parent_id'] = Variable(parentId); + } + if (!nullToAbsent || quotedMessageId != null) { + map['quoted_message_id'] = Variable(quotedMessageId); + } + if (!nullToAbsent || replyCount != null) { + map['reply_count'] = Variable(replyCount); + } + if (!nullToAbsent || showInChannel != null) { + map['show_in_channel'] = Variable(showInChannel); + } + if (!nullToAbsent || shadowed != null) { + map['shadowed'] = Variable(shadowed); + } + if (!nullToAbsent || command != null) { + map['command'] = Variable(command); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || pinned != null) { + map['pinned'] = Variable(pinned); + } + if (!nullToAbsent || pinnedAt != null) { + map['pinned_at'] = Variable(pinnedAt); + } + if (!nullToAbsent || pinExpires != null) { + map['pin_expires'] = Variable(pinExpires); + } + if (!nullToAbsent || pinnedByUserId != null) { + map['pinned_by_user_id'] = Variable(pinnedByUserId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || extraData != null) { + final converter = $PinnedMessagesTable.$converter5; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + factory PinnedMessageEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return PinnedMessageEntity( + id: serializer.fromJson(json['id']), + messageText: serializer.fromJson(json['messageText']), + attachments: serializer.fromJson>(json['attachments']), + status: serializer.fromJson(json['status']), + type: serializer.fromJson(json['type']), + mentionedUsers: serializer.fromJson>(json['mentionedUsers']), + reactionCounts: + serializer.fromJson>(json['reactionCounts']), + reactionScores: + serializer.fromJson>(json['reactionScores']), + parentId: serializer.fromJson(json['parentId']), + quotedMessageId: serializer.fromJson(json['quotedMessageId']), + replyCount: serializer.fromJson(json['replyCount']), + showInChannel: serializer.fromJson(json['showInChannel']), + shadowed: serializer.fromJson(json['shadowed']), + command: serializer.fromJson(json['command']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + userId: serializer.fromJson(json['userId']), + pinned: serializer.fromJson(json['pinned']), + pinnedAt: serializer.fromJson(json['pinnedAt']), + pinExpires: serializer.fromJson(json['pinExpires']), + pinnedByUserId: serializer.fromJson(json['pinnedByUserId']), + channelCid: serializer.fromJson(json['channelCid']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageText': serializer.toJson(messageText), + 'attachments': serializer.toJson>(attachments), + 'status': serializer.toJson(status), + 'type': serializer.toJson(type), + 'mentionedUsers': serializer.toJson>(mentionedUsers), + 'reactionCounts': serializer.toJson>(reactionCounts), + 'reactionScores': serializer.toJson>(reactionScores), + 'parentId': serializer.toJson(parentId), + 'quotedMessageId': serializer.toJson(quotedMessageId), + 'replyCount': serializer.toJson(replyCount), + 'showInChannel': serializer.toJson(showInChannel), + 'shadowed': serializer.toJson(shadowed), + 'command': serializer.toJson(command), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'userId': serializer.toJson(userId), + 'pinned': serializer.toJson(pinned), + 'pinnedAt': serializer.toJson(pinnedAt), + 'pinExpires': serializer.toJson(pinExpires), + 'pinnedByUserId': serializer.toJson(pinnedByUserId), + 'channelCid': serializer.toJson(channelCid), + 'extraData': serializer.toJson>(extraData), + }; + } + + PinnedMessageEntity copyWith( + {String id, + Value messageText = const Value.absent(), + Value> attachments = const Value.absent(), + Value status = const Value.absent(), + Value type = const Value.absent(), + Value> mentionedUsers = const Value.absent(), + Value> reactionCounts = const Value.absent(), + Value> reactionScores = const Value.absent(), + Value parentId = const Value.absent(), + Value quotedMessageId = const Value.absent(), + Value replyCount = const Value.absent(), + Value showInChannel = const Value.absent(), + Value shadowed = const Value.absent(), + Value command = const Value.absent(), + DateTime createdAt, + Value updatedAt = const Value.absent(), + Value deletedAt = const Value.absent(), + Value userId = const Value.absent(), + bool pinned, + Value pinnedAt = const Value.absent(), + Value pinExpires = const Value.absent(), + Value pinnedByUserId = const Value.absent(), + Value channelCid = const Value.absent(), + Value> extraData = const Value.absent()}) => + PinnedMessageEntity( + id: id ?? this.id, + messageText: messageText.present ? messageText.value : this.messageText, + attachments: attachments.present ? attachments.value : this.attachments, + status: status.present ? status.value : this.status, + type: type.present ? type.value : this.type, + mentionedUsers: + mentionedUsers.present ? mentionedUsers.value : this.mentionedUsers, + reactionCounts: + reactionCounts.present ? reactionCounts.value : this.reactionCounts, + reactionScores: + reactionScores.present ? reactionScores.value : this.reactionScores, + parentId: parentId.present ? parentId.value : this.parentId, + quotedMessageId: quotedMessageId.present + ? quotedMessageId.value + : this.quotedMessageId, + replyCount: replyCount.present ? replyCount.value : this.replyCount, + showInChannel: + showInChannel.present ? showInChannel.value : this.showInChannel, + shadowed: shadowed.present ? shadowed.value : this.shadowed, + command: command.present ? command.value : this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + userId: userId.present ? userId.value : this.userId, + pinned: pinned ?? this.pinned, + pinnedAt: pinnedAt.present ? pinnedAt.value : this.pinnedAt, + pinExpires: pinExpires.present ? pinExpires.value : this.pinExpires, + pinnedByUserId: + pinnedByUserId.present ? pinnedByUserId.value : this.pinnedByUserId, + channelCid: channelCid.present ? channelCid.value : this.channelCid, + extraData: extraData.present ? extraData.value : this.extraData, + ); + @override + String toString() { + return (StringBuffer('PinnedMessageEntity(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachments: $attachments, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('mentionedUsers: $mentionedUsers, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('pinned: $pinned, ') + ..write('pinnedAt: $pinnedAt, ') + ..write('pinExpires: $pinExpires, ') + ..write('pinnedByUserId: $pinnedByUserId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + messageText.hashCode, + $mrjc( + attachments.hashCode, + $mrjc( + status.hashCode, + $mrjc( + type.hashCode, + $mrjc( + mentionedUsers.hashCode, + $mrjc( + reactionCounts.hashCode, + $mrjc( + reactionScores.hashCode, + $mrjc( + parentId.hashCode, + $mrjc( + quotedMessageId.hashCode, + $mrjc( + replyCount.hashCode, + $mrjc( + showInChannel.hashCode, + $mrjc( + shadowed.hashCode, + $mrjc( + command.hashCode, + $mrjc( + createdAt + .hashCode, + $mrjc( + updatedAt + .hashCode, + $mrjc( + deletedAt + .hashCode, + $mrjc( + userId + .hashCode, + $mrjc( + pinned.hashCode, + $mrjc(pinnedAt.hashCode, $mrjc(pinExpires.hashCode, $mrjc(pinnedByUserId.hashCode, $mrjc(channelCid.hashCode, extraData.hashCode)))))))))))))))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is PinnedMessageEntity && + other.id == this.id && + other.messageText == this.messageText && + other.attachments == this.attachments && + other.status == this.status && + other.type == this.type && + other.mentionedUsers == this.mentionedUsers && + other.reactionCounts == this.reactionCounts && + other.reactionScores == this.reactionScores && + other.parentId == this.parentId && + other.quotedMessageId == this.quotedMessageId && + other.replyCount == this.replyCount && + other.showInChannel == this.showInChannel && + other.shadowed == this.shadowed && + other.command == this.command && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.userId == this.userId && + other.pinned == this.pinned && + other.pinnedAt == this.pinnedAt && + other.pinExpires == this.pinExpires && + other.pinnedByUserId == this.pinnedByUserId && + other.channelCid == this.channelCid && + other.extraData == this.extraData); +} + +class PinnedMessagesCompanion extends UpdateCompanion { + final Value id; + final Value messageText; + final Value> attachments; + final Value status; + final Value type; + final Value> mentionedUsers; + final Value> reactionCounts; + final Value> reactionScores; + final Value parentId; + final Value quotedMessageId; + final Value replyCount; + final Value showInChannel; + final Value shadowed; + final Value command; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value userId; + final Value pinned; + final Value pinnedAt; + final Value pinExpires; + final Value pinnedByUserId; + final Value channelCid; + final Value> extraData; + const PinnedMessagesCompanion({ + this.id = const Value.absent(), + this.messageText = const Value.absent(), + this.attachments = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.mentionedUsers = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.pinned = const Value.absent(), + this.pinnedAt = const Value.absent(), + this.pinExpires = const Value.absent(), + this.pinnedByUserId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }); + PinnedMessagesCompanion.insert({ + @required String id, + this.messageText = const Value.absent(), + this.attachments = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.mentionedUsers = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + @required DateTime createdAt, + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.pinned = const Value.absent(), + this.pinnedAt = const Value.absent(), + this.pinExpires = const Value.absent(), + this.pinnedByUserId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt); + static Insertable custom({ + Expression id, + Expression messageText, + Expression attachments, + Expression status, + Expression type, + Expression mentionedUsers, + Expression reactionCounts, + Expression reactionScores, + Expression parentId, + Expression quotedMessageId, + Expression replyCount, + Expression showInChannel, + Expression shadowed, + Expression command, + Expression createdAt, + Expression updatedAt, + Expression deletedAt, + Expression userId, + Expression pinned, + Expression pinnedAt, + Expression pinExpires, + Expression pinnedByUserId, + Expression channelCid, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageText != null) 'message_text': messageText, + if (attachments != null) 'attachments': attachments, + if (status != null) 'status': status, + if (type != null) 'type': type, + if (mentionedUsers != null) 'mentioned_users': mentionedUsers, + if (reactionCounts != null) 'reaction_counts': reactionCounts, + if (reactionScores != null) 'reaction_scores': reactionScores, + if (parentId != null) 'parent_id': parentId, + if (quotedMessageId != null) 'quoted_message_id': quotedMessageId, + if (replyCount != null) 'reply_count': replyCount, + if (showInChannel != null) 'show_in_channel': showInChannel, + if (shadowed != null) 'shadowed': shadowed, + if (command != null) 'command': command, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (userId != null) 'user_id': userId, + if (pinned != null) 'pinned': pinned, + if (pinnedAt != null) 'pinned_at': pinnedAt, + if (pinExpires != null) 'pin_expires': pinExpires, + if (pinnedByUserId != null) 'pinned_by_user_id': pinnedByUserId, + if (channelCid != null) 'channel_cid': channelCid, + if (extraData != null) 'extra_data': extraData, + }); + } + + PinnedMessagesCompanion copyWith( + {Value id, + Value messageText, + Value> attachments, + Value status, + Value type, + Value> mentionedUsers, + Value> reactionCounts, + Value> reactionScores, + Value parentId, + Value quotedMessageId, + Value replyCount, + Value showInChannel, + Value shadowed, + Value command, + Value createdAt, + Value updatedAt, + Value deletedAt, + Value userId, + Value pinned, + Value pinnedAt, + Value pinExpires, + Value pinnedByUserId, + Value channelCid, + Value> extraData}) { + return PinnedMessagesCompanion( + id: id ?? this.id, + messageText: messageText ?? this.messageText, + attachments: attachments ?? this.attachments, + status: status ?? this.status, + type: type ?? this.type, + mentionedUsers: mentionedUsers ?? this.mentionedUsers, + reactionCounts: reactionCounts ?? this.reactionCounts, + reactionScores: reactionScores ?? this.reactionScores, + parentId: parentId ?? this.parentId, + quotedMessageId: quotedMessageId ?? this.quotedMessageId, + replyCount: replyCount ?? this.replyCount, + showInChannel: showInChannel ?? this.showInChannel, + shadowed: shadowed ?? this.shadowed, + command: command ?? this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + userId: userId ?? this.userId, + pinned: pinned ?? this.pinned, + pinnedAt: pinnedAt ?? this.pinnedAt, + pinExpires: pinExpires ?? this.pinExpires, + pinnedByUserId: pinnedByUserId ?? this.pinnedByUserId, + channelCid: channelCid ?? this.channelCid, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageText.present) { + map['message_text'] = Variable(messageText.value); + } + if (attachments.present) { + final converter = $PinnedMessagesTable.$converter0; + map['attachments'] = + Variable(converter.mapToSql(attachments.value)); + } + if (status.present) { + final converter = $PinnedMessagesTable.$converter1; + map['status'] = Variable(converter.mapToSql(status.value)); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (mentionedUsers.present) { + final converter = $PinnedMessagesTable.$converter2; + map['mentioned_users'] = + Variable(converter.mapToSql(mentionedUsers.value)); + } + if (reactionCounts.present) { + final converter = $PinnedMessagesTable.$converter3; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts.value)); + } + if (reactionScores.present) { + final converter = $PinnedMessagesTable.$converter4; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores.value)); + } + if (parentId.present) { + map['parent_id'] = Variable(parentId.value); + } + if (quotedMessageId.present) { + map['quoted_message_id'] = Variable(quotedMessageId.value); + } + if (replyCount.present) { + map['reply_count'] = Variable(replyCount.value); + } + if (showInChannel.present) { + map['show_in_channel'] = Variable(showInChannel.value); + } + if (shadowed.present) { + map['shadowed'] = Variable(shadowed.value); + } + if (command.present) { + map['command'] = Variable(command.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (pinnedAt.present) { + map['pinned_at'] = Variable(pinnedAt.value); + } + if (pinExpires.present) { + map['pin_expires'] = Variable(pinExpires.value); + } + if (pinnedByUserId.present) { + map['pinned_by_user_id'] = Variable(pinnedByUserId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (extraData.present) { + final converter = $PinnedMessagesTable.$converter5; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PinnedMessagesCompanion(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachments: $attachments, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('mentionedUsers: $mentionedUsers, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('pinned: $pinned, ') + ..write('pinnedAt: $pinnedAt, ') + ..write('pinExpires: $pinExpires, ') + ..write('pinnedByUserId: $pinnedByUserId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $PinnedMessagesTable extends PinnedMessages + with TableInfo<$PinnedMessagesTable, PinnedMessageEntity> { + final GeneratedDatabase _db; + final String _alias; + $PinnedMessagesTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _messageTextMeta = + const VerificationMeta('messageText'); + GeneratedTextColumn _messageText; + @override + GeneratedTextColumn get messageText => + _messageText ??= _constructMessageText(); + GeneratedTextColumn _constructMessageText() { + return GeneratedTextColumn( + 'message_text', + $tableName, + true, + ); + } + + final VerificationMeta _attachmentsMeta = + const VerificationMeta('attachments'); + GeneratedTextColumn _attachments; + @override + GeneratedTextColumn get attachments => + _attachments ??= _constructAttachments(); + GeneratedTextColumn _constructAttachments() { + return GeneratedTextColumn( + 'attachments', + $tableName, + true, + ); + } + + final VerificationMeta _statusMeta = const VerificationMeta('status'); + GeneratedIntColumn _status; + @override + GeneratedIntColumn get status => _status ??= _constructStatus(); + GeneratedIntColumn _constructStatus() { + return GeneratedIntColumn( + 'status', + $tableName, + true, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + true, + ); + } + + final VerificationMeta _mentionedUsersMeta = + const VerificationMeta('mentionedUsers'); + GeneratedTextColumn _mentionedUsers; + @override + GeneratedTextColumn get mentionedUsers => + _mentionedUsers ??= _constructMentionedUsers(); + GeneratedTextColumn _constructMentionedUsers() { + return GeneratedTextColumn( + 'mentioned_users', + $tableName, + true, + ); + } + + final VerificationMeta _reactionCountsMeta = + const VerificationMeta('reactionCounts'); + GeneratedTextColumn _reactionCounts; + @override + GeneratedTextColumn get reactionCounts => + _reactionCounts ??= _constructReactionCounts(); + GeneratedTextColumn _constructReactionCounts() { + return GeneratedTextColumn( + 'reaction_counts', + $tableName, + true, + ); + } + + final VerificationMeta _reactionScoresMeta = + const VerificationMeta('reactionScores'); + GeneratedTextColumn _reactionScores; + @override + GeneratedTextColumn get reactionScores => + _reactionScores ??= _constructReactionScores(); + GeneratedTextColumn _constructReactionScores() { + return GeneratedTextColumn( + 'reaction_scores', + $tableName, + true, + ); + } + + final VerificationMeta _parentIdMeta = const VerificationMeta('parentId'); + GeneratedTextColumn _parentId; + @override + GeneratedTextColumn get parentId => _parentId ??= _constructParentId(); + GeneratedTextColumn _constructParentId() { + return GeneratedTextColumn( + 'parent_id', + $tableName, + true, + ); + } + + final VerificationMeta _quotedMessageIdMeta = + const VerificationMeta('quotedMessageId'); + GeneratedTextColumn _quotedMessageId; + @override + GeneratedTextColumn get quotedMessageId => + _quotedMessageId ??= _constructQuotedMessageId(); + GeneratedTextColumn _constructQuotedMessageId() { + return GeneratedTextColumn( + 'quoted_message_id', + $tableName, + true, + ); + } + + final VerificationMeta _replyCountMeta = const VerificationMeta('replyCount'); + GeneratedIntColumn _replyCount; + @override + GeneratedIntColumn get replyCount => _replyCount ??= _constructReplyCount(); + GeneratedIntColumn _constructReplyCount() { + return GeneratedIntColumn( + 'reply_count', + $tableName, + true, + ); + } + + final VerificationMeta _showInChannelMeta = + const VerificationMeta('showInChannel'); + GeneratedBoolColumn _showInChannel; + @override + GeneratedBoolColumn get showInChannel => + _showInChannel ??= _constructShowInChannel(); + GeneratedBoolColumn _constructShowInChannel() { + return GeneratedBoolColumn( + 'show_in_channel', + $tableName, + true, + ); + } + + final VerificationMeta _shadowedMeta = const VerificationMeta('shadowed'); + GeneratedBoolColumn _shadowed; + @override + GeneratedBoolColumn get shadowed => _shadowed ??= _constructShadowed(); + GeneratedBoolColumn _constructShadowed() { + return GeneratedBoolColumn( + 'shadowed', + $tableName, + true, + ); + } + + final VerificationMeta _commandMeta = const VerificationMeta('command'); + GeneratedTextColumn _command; + @override + GeneratedTextColumn get command => _command ??= _constructCommand(); + GeneratedTextColumn _constructCommand() { + return GeneratedTextColumn( + 'command', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); + GeneratedDateTimeColumn _deletedAt; + @override + GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); + GeneratedDateTimeColumn _constructDeletedAt() { + return GeneratedDateTimeColumn( + 'deleted_at', + $tableName, + true, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + true, + ); + } + + final VerificationMeta _pinnedMeta = const VerificationMeta('pinned'); + GeneratedBoolColumn _pinned; + @override + GeneratedBoolColumn get pinned => _pinned ??= _constructPinned(); + GeneratedBoolColumn _constructPinned() { + return GeneratedBoolColumn('pinned', $tableName, false, + defaultValue: const Constant(false)); + } + + final VerificationMeta _pinnedAtMeta = const VerificationMeta('pinnedAt'); + GeneratedDateTimeColumn _pinnedAt; + @override + GeneratedDateTimeColumn get pinnedAt => _pinnedAt ??= _constructPinnedAt(); + GeneratedDateTimeColumn _constructPinnedAt() { + return GeneratedDateTimeColumn( + 'pinned_at', + $tableName, + true, + ); + } + + final VerificationMeta _pinExpiresMeta = const VerificationMeta('pinExpires'); + GeneratedDateTimeColumn _pinExpires; + @override + GeneratedDateTimeColumn get pinExpires => + _pinExpires ??= _constructPinExpires(); + GeneratedDateTimeColumn _constructPinExpires() { + return GeneratedDateTimeColumn( + 'pin_expires', + $tableName, + true, + ); + } + + final VerificationMeta _pinnedByUserIdMeta = + const VerificationMeta('pinnedByUserId'); + GeneratedTextColumn _pinnedByUserId; + @override + GeneratedTextColumn get pinnedByUserId => + _pinnedByUserId ??= _constructPinnedByUserId(); + GeneratedTextColumn _constructPinnedByUserId() { + return GeneratedTextColumn( + 'pinned_by_user_id', + $tableName, + true, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn('channel_cid', $tableName, true, + $customConstraints: + 'NULLABLE REFERENCES channels(cid) ON DELETE CASCADE'); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => [ + id, + messageText, + attachments, + status, + type, + mentionedUsers, + reactionCounts, + reactionScores, + parentId, + quotedMessageId, + replyCount, + showInChannel, + shadowed, + command, + createdAt, + updatedAt, + deletedAt, + userId, + pinned, + pinnedAt, + pinExpires, + pinnedByUserId, + channelCid, + extraData + ]; + @override + $PinnedMessagesTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'pinned_messages'; + @override + final String actualTableName = 'pinned_messages'; + @override + VerificationContext validateIntegrity( + Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('message_text')) { + context.handle( + _messageTextMeta, + messageText.isAcceptableOrUnknown( + data['message_text'], _messageTextMeta)); + } + context.handle(_attachmentsMeta, const VerificationResult.success()); + context.handle(_statusMeta, const VerificationResult.success()); + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } + context.handle(_mentionedUsersMeta, const VerificationResult.success()); + context.handle(_reactionCountsMeta, const VerificationResult.success()); + context.handle(_reactionScoresMeta, const VerificationResult.success()); + if (data.containsKey('parent_id')) { + context.handle(_parentIdMeta, + parentId.isAcceptableOrUnknown(data['parent_id'], _parentIdMeta)); + } + if (data.containsKey('quoted_message_id')) { + context.handle( + _quotedMessageIdMeta, + quotedMessageId.isAcceptableOrUnknown( + data['quoted_message_id'], _quotedMessageIdMeta)); + } + if (data.containsKey('reply_count')) { + context.handle( + _replyCountMeta, + replyCount.isAcceptableOrUnknown( + data['reply_count'], _replyCountMeta)); + } + if (data.containsKey('show_in_channel')) { + context.handle( + _showInChannelMeta, + showInChannel.isAcceptableOrUnknown( + data['show_in_channel'], _showInChannelMeta)); + } + if (data.containsKey('shadowed')) { + context.handle(_shadowedMeta, + shadowed.isAcceptableOrUnknown(data['shadowed'], _shadowedMeta)); + } + if (data.containsKey('command')) { + context.handle(_commandMeta, + command.isAcceptableOrUnknown(data['command'], _commandMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('deleted_at')) { + context.handle(_deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } + if (data.containsKey('pinned')) { + context.handle(_pinnedMeta, + pinned.isAcceptableOrUnknown(data['pinned'], _pinnedMeta)); + } + if (data.containsKey('pinned_at')) { + context.handle(_pinnedAtMeta, + pinnedAt.isAcceptableOrUnknown(data['pinned_at'], _pinnedAtMeta)); + } + if (data.containsKey('pin_expires')) { + context.handle( + _pinExpiresMeta, + pinExpires.isAcceptableOrUnknown( + data['pin_expires'], _pinExpiresMeta)); + } + if (data.containsKey('pinned_by_user_id')) { + context.handle( + _pinnedByUserIdMeta, + pinnedByUserId.isAcceptableOrUnknown( + data['pinned_by_user_id'], _pinnedByUserIdMeta)); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {id}; + @override + PinnedMessageEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return PinnedMessageEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $PinnedMessagesTable createAlias(String alias) { + return $PinnedMessagesTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + ListConverter(); + static TypeConverter $converter1 = + MessageSendingStatusConverter(); + static TypeConverter, String> $converter2 = + ListConverter(); + static TypeConverter, String> $converter3 = + MapConverter(); + static TypeConverter, String> $converter4 = + MapConverter(); + static TypeConverter, String> $converter5 = + MapConverter(); +} + class ReactionEntity extends DataClass implements Insertable { final String userId; final String messageId; @@ -3979,6 +5343,9 @@ abstract class _$MoorChatDatabase extends GeneratedDatabase { $ChannelsTable get channels => _channels ??= $ChannelsTable(this); $MessagesTable _messages; $MessagesTable get messages => _messages ??= $MessagesTable(this); + $PinnedMessagesTable _pinnedMessages; + $PinnedMessagesTable get pinnedMessages => + _pinnedMessages ??= $PinnedMessagesTable(this); $ReactionsTable _reactions; $ReactionsTable get reactions => _reactions ??= $ReactionsTable(this); $UsersTable _users; @@ -4001,6 +5368,9 @@ abstract class _$MoorChatDatabase extends GeneratedDatabase { MessageDao _messageDao; MessageDao get messageDao => _messageDao ??= MessageDao(this as MoorChatDatabase); + PinnedMessageDao _pinnedMessageDao; + PinnedMessageDao get pinnedMessageDao => + _pinnedMessageDao ??= PinnedMessageDao(this as MoorChatDatabase); MemberDao _memberDao; MemberDao get memberDao => _memberDao ??= MemberDao(this as MoorChatDatabase); ReactionDao _reactionDao; @@ -4020,6 +5390,7 @@ abstract class _$MoorChatDatabase extends GeneratedDatabase { List get allSchemaEntities => [ channels, messages, + pinnedMessages, reactions, users, members, diff --git a/packages/stream_chat_persistence/lib/src/entity/entity.dart b/packages/stream_chat_persistence/lib/src/entity/entity.dart index 8751f538..ca9d04cb 100644 --- a/packages/stream_chat_persistence/lib/src/entity/entity.dart +++ b/packages/stream_chat_persistence/lib/src/entity/entity.dart @@ -1,5 +1,6 @@ export 'channels.dart'; export 'messages.dart'; +export 'pinned_messages.dart'; export 'reactions.dart'; export 'users.dart'; export 'members.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/messages.dart b/packages/stream_chat_persistence/lib/src/entity/messages.dart index 8a151ae6..0350d9de 100644 --- a/packages/stream_chat_persistence/lib/src/entity/messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/messages.dart @@ -64,6 +64,18 @@ class Messages extends Table { /// Id of the User who sent the message TextColumn get userId => text().nullable()(); + /// Whether the message is pinned or not + BoolColumn get pinned => boolean().withDefault(const Constant(false))(); + + /// The DateTime at which the message was pinned + DateTimeColumn get pinnedAt => dateTime().nullable()(); + + /// The DateTime on which the message pin expires + DateTimeColumn get pinExpires => dateTime().nullable()(); + + /// Id of the User who pinned the message + TextColumn get pinnedByUserId => text().nullable()(); + /// The channel cid of which this message is part of TextColumn get channelCid => text().nullable().customConstraint( 'NULLABLE REFERENCES channels(cid) ON DELETE CASCADE')(); diff --git a/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart new file mode 100644 index 00000000..f6956f54 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart @@ -0,0 +1,7 @@ +import 'package:moor/moor.dart'; + +import 'messages.dart'; + +/// Represents a [PinnedMessages] table in [MoorChatDatabase]. +@DataClassName('PinnedMessageEntity') +class PinnedMessages extends Messages {} diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart index 7d0e152f..3e2520fb 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -28,11 +28,13 @@ extension ChannelEntityX on ChannelEntity { List members, List reads, List messages, + List pinnedMessages, }) { return ChannelState( members: members, read: reads, messages: messages, + pinnedMessages: pinnedMessages, channel: toChannelModel(createdBy: createdBy), ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart index 8d19729d..cdc31e05 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart @@ -5,3 +5,4 @@ export 'event_mapper.dart'; export 'member_mapper.dart'; export 'read_mapper.dart'; export 'message_mapper.dart'; +export 'pinned_message_mapper.dart'; diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart index c8bda4e6..5acf1a84 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -8,6 +8,7 @@ extension MessageEntityX on MessageEntity { /// Maps a [MessageEntity] into [Message] Message toMessage({ User user, + User pinnedBy, List latestReactions, List ownReactions, Message quotedMessage, @@ -37,6 +38,10 @@ extension MessageEntityX on MessageEntity { text: messageText, user: user, deletedAt: deletedAt, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedBy: pinnedBy, ); } } @@ -67,6 +72,10 @@ extension MessageX on Message { userId: user?.id, deletedAt: deletedAt, messageText: text, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedByUserId: pinnedBy?.id, ); } } diff --git a/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart new file mode 100644 index 00000000..1abe896f --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart @@ -0,0 +1,81 @@ +import 'dart:convert'; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// Useful mapping functions for [PinnedMessageEntity] +extension PinnedMessageEntityX on PinnedMessageEntity { + /// Maps a [PinnedMessageEntity] into [Message] + Message toMessage({ + User user, + User pinnedBy, + List latestReactions, + List ownReactions, + Message quotedMessage, + }) { + return Message( + shadowed: shadowed, + latestReactions: latestReactions, + ownReactions: ownReactions, + attachments: attachments?.map((it) { + final json = jsonDecode(it); + return Attachment.fromData(json); + })?.toList(), + createdAt: createdAt, + extraData: extraData, + updatedAt: updatedAt, + id: id, + type: type, + status: status, + command: command, + parentId: parentId, + quotedMessageId: quotedMessageId, + quotedMessage: quotedMessage, + reactionCounts: reactionCounts, + reactionScores: reactionScores, + replyCount: replyCount, + showInChannel: showInChannel, + text: messageText, + user: user, + deletedAt: deletedAt, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedBy: pinnedBy, + ); + } +} + +/// Useful mapping functions for [Message] +extension PMessageX on Message { + /// Maps a [Message] into [PinnedMessageEntity] + PinnedMessageEntity toPinnedEntity({String cid}) { + return PinnedMessageEntity( + id: id, + attachments: attachments?.map((it) { + return jsonEncode(it.toData()); + })?.toList(), + channelCid: cid, + type: type, + parentId: parentId, + quotedMessageId: quotedMessageId, + command: command, + createdAt: createdAt, + shadowed: shadowed, + showInChannel: showInChannel, + replyCount: replyCount, + reactionScores: reactionScores, + reactionCounts: reactionCounts, + status: status, + updatedAt: updatedAt, + extraData: extraData, + userId: user?.id, + deletedAt: deletedAt, + messageText: text, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedByUserId: pinnedBy?.id, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index 0962c9ac..50d17111 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -81,11 +81,21 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return _db.messageDao.deleteMessageByIds(messageIds); } + @override + Future deletePinnedMessageByIds(List messageIds) { + return _db.pinnedMessageDao.deleteMessageByIds(messageIds); + } + @override Future deleteMessageByCids(List cids) { return _db.messageDao.deleteMessageByCids(cids); } + @override + Future deletePinnedMessageByCids(List cids) { + return _db.pinnedMessageDao.deleteMessageByCids(cids); + } + @override Future> getMembersByCid(String cid) { return _db.memberDao.getMembersByCid(cid); @@ -107,6 +117,17 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { ); } + @override + Future> getPinnedMessagesByCid( + String cid, { + PaginationParams messagePagination, + }) { + return _db.pinnedMessageDao.getMessagesByCid( + cid, + messagePagination: messagePagination, + ); + } + @override Future> getReadsByCid(String cid) { return _db.readDao.getReadsByCid(cid); @@ -178,6 +199,11 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return _db.messageDao.updateMessages(cid, messages); } + @override + Future updatePinnedMessages(String cid, List messages) { + return _db.pinnedMessageDao.updateMessages(cid, messages); + } + @override Future updateReactions(List reactions) { return _db.reactionDao.updateReactions(reactions); diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 0517b02e..9551507e 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -13,7 +13,8 @@ dependencies: path: ^1.7.0 path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.4.0+1 - stream_chat: ^1.2.0-beta + stream_chat: + path: ../stream_chat dev_dependencies: test: ^1.15.7 From 6c501d875ba248c04b8a6d07fe998e6136fa5afb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 22 Feb 2021 19:46:30 +0530 Subject: [PATCH 2/8] [LLC -> Channel] Expose channel pinned messages in the form of getter and a stream Signed-off-by: Sahil Kumar --- packages/stream_chat/lib/src/api/channel.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index e7a38922..03be0abf 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -1502,6 +1502,13 @@ class ChannelClientState { Stream> get messagesStream => channelStateStream.map((cs) => cs.messages); + /// Channel pinned message list + List get pinnedMessages => _channelState.pinnedMessages; + + /// Channel pinned message list as a stream + Stream> get pinnedMessagesStream => + channelStateStream.map((cs) => cs.pinnedMessages); + /// Get channel last message Message get lastMessage => _channelState.messages?.isNotEmpty == true ? _channelState.messages.last From 750c5305f46e9af977aab687bd889d1bf0449eb4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 23 Feb 2021 13:19:31 +0100 Subject: [PATCH 3/8] update pinned messages --- packages/stream_chat/lib/src/api/channel.dart | 40 +- .../ios/Runner.xcodeproj/project.pbxproj | 563 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + .../example/pubspec.yaml | 3 +- 4 files changed, 603 insertions(+), 6 deletions(-) create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 03be0abf..76611438 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -41,6 +41,7 @@ class Channel { state = ChannelClientState(this, channelState); _initializedCompleter.complete(true); _startCleaning(); + _startCleaningPinnedMessages(); _client.logger.info('New Channel instance initialized created'); } @@ -845,6 +846,7 @@ class Channel { _initializedCompleter.complete(true); } _startCleaning(); + _startCleaningPinnedMessages(); } /// Stop watching the channel @@ -1185,13 +1187,12 @@ class Channel { } Timer _cleaningTimer; - void _startCleaning() { if (config?.typingEvents == false) { return; } - _cleaningTimer = Timer.periodic(Duration(milliseconds: 500), (_) { + _cleaningTimer = Timer.periodic(Duration(seconds: 1), (_) { final now = DateTime.now(); if (_lastTypingEvent != null && @@ -1203,8 +1204,22 @@ class Channel { }); } + Timer _pinnedMessagesTimer; + void _startCleaningPinnedMessages() { + _pinnedMessagesTimer = Timer.periodic(Duration(seconds: 30), (_) { + final now = DateTime.now(); + final messageExpired = state.channelState.pinnedMessages + .any((m) => m.pinExpires.isBefore(now)); + if (messageExpired) { + state._channelState = + state._channelState.copyWith(pinnedMessages: state.pinnedMessages); + } + }); + } + /// Call this method to dispose the channel client void dispose() { + _pinnedMessagesTimer.cancel(); _cleaningTimer.cancel(); state.dispose(); } @@ -1413,6 +1428,15 @@ class ChannelClientState { ..removeWhere((it) => it.userId != userId), ); addMessage(message); + + if (message.pinned == true) { + _channelState = _channelState.copyWith( + pinnedMessages: [ + ..._channelState.pinnedMessages ?? [], + message, + ], + ); + } })); } @@ -1503,11 +1527,12 @@ class ChannelClientState { channelStateStream.map((cs) => cs.messages); /// Channel pinned message list - List get pinnedMessages => _channelState.pinnedMessages; + List get pinnedMessages => + _channelState.pinnedMessages?.where(_pinIsValid())?.toList(); /// Channel pinned message list as a stream - Stream> get pinnedMessagesStream => - channelStateStream.map((cs) => cs.pinnedMessages); + Stream> get pinnedMessagesStream => channelStateStream + .map((cs) => cs.pinnedMessages?.where(_pinIsValid())?.toList()); /// Get channel last message Message get lastMessage => _channelState.messages?.isNotEmpty == true @@ -1769,3 +1794,8 @@ class ChannelClientState { _typingEventsController.close(); } } + +bool Function(Message) _pinIsValid() { + final now = DateTime.now(); + return (Message m) => m.pinExpires.isAfter(now); +} diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..261aa5a8 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,563 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0E9B23A7BA08E142FA5000CF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D76F8024ABE1070895D659BA /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3F6A054EEDAF06BCF649C130 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 6FE1ECA061EBB001F6BCE8B7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D76F8024ABE1070895D659BA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EC2A45E9198C1011BED23834 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E9B23A7BA08E142FA5000CF /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 04AAB960E493BD92262BBF82 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D76F8024ABE1070895D659BA /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 8559384DCD98ED6067CEF8CB /* Pods */ = { + isa = PBXGroup; + children = ( + 3F6A054EEDAF06BCF649C130 /* Pods-Runner.debug.xcconfig */, + EC2A45E9198C1011BED23834 /* Pods-Runner.release.xcconfig */, + 6FE1ECA061EBB001F6BCE8B7 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 8559384DCD98ED6067CEF8CB /* Pods */, + 04AAB960E493BD92262BBF82 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + C1EE41B94EADE099F7AF3A1C /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + BD38DACC9A0AD429D9ED9939 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + BD38DACC9A0AD429D9ED9939 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C1EE41B94EADE099F7AF3A1C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/stream_chat_persistence/example/pubspec.yaml b/packages/stream_chat_persistence/example/pubspec.yaml index 4298e23a..5008566b 100644 --- a/packages/stream_chat_persistence/example/pubspec.yaml +++ b/packages/stream_chat_persistence/example/pubspec.yaml @@ -11,7 +11,8 @@ dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.0 - stream_chat: ^1.1.0-beta + stream_chat: + path: ../../stream_chat stream_chat_persistence: path: ../ From b66a16c7f113ae79bffda30a25aa3a5e72534f3b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 23 Feb 2021 13:37:13 +0100 Subject: [PATCH 4/8] clear expired pinned messages --- packages/stream_chat/lib/src/api/channel.dart | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 76611438..024f8724 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -1208,11 +1208,21 @@ class Channel { void _startCleaningPinnedMessages() { _pinnedMessagesTimer = Timer.periodic(Duration(seconds: 30), (_) { final now = DateTime.now(); - final messageExpired = state.channelState.pinnedMessages - .any((m) => m.pinExpires.isBefore(now)); - if (messageExpired) { - state._channelState = - state._channelState.copyWith(pinnedMessages: state.pinnedMessages); + final expiredMessages = state.channelState.pinnedMessages + ?.where((m) => m.pinExpires?.isBefore(now) == true) + ?.toList() ?? + []; + if (expiredMessages.isNotEmpty) { + expiredMessages.forEach((m) => state.addMessage(m.copyWith( + pinExpires: null, + pinned: false, + pinnedAt: null, + pinnedBy: null, + ))); + + state._channelState = state._channelState.copyWith( + pinnedMessages: state.pinnedMessages.where(_pinIsValid()).toList(), + ); } }); } @@ -1527,12 +1537,11 @@ class ChannelClientState { channelStateStream.map((cs) => cs.messages); /// Channel pinned message list - List get pinnedMessages => - _channelState.pinnedMessages?.where(_pinIsValid())?.toList(); + List get pinnedMessages => _channelState.pinnedMessages?.toList(); /// Channel pinned message list as a stream - Stream> get pinnedMessagesStream => channelStateStream - .map((cs) => cs.pinnedMessages?.where(_pinIsValid())?.toList()); + Stream> get pinnedMessagesStream => + channelStateStream.map((cs) => cs.pinnedMessages?.toList()); /// Get channel last message Message get lastMessage => _channelState.messages?.isNotEmpty == true From e0e25e7caf6085985003fcbe325d72189b3c8afe Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 23 Feb 2021 17:42:52 +0100 Subject: [PATCH 5/8] move cleaning logic to channel state --- packages/stream_chat/lib/src/api/channel.dart | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 024f8724..758d0317 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -40,9 +40,6 @@ class Channel { state = ChannelClientState(this, channelState); _initializedCompleter.complete(true); - _startCleaning(); - _startCleaningPinnedMessages(); - _client.logger.info('New Channel instance initialized created'); } @@ -845,8 +842,6 @@ class Channel { if (!_initializedCompleter.isCompleted) { _initializedCompleter.complete(true); } - _startCleaning(); - _startCleaningPinnedMessages(); } /// Stop watching the channel @@ -1186,51 +1181,8 @@ class Channel { )); } - Timer _cleaningTimer; - void _startCleaning() { - if (config?.typingEvents == false) { - return; - } - - _cleaningTimer = Timer.periodic(Duration(seconds: 1), (_) { - final now = DateTime.now(); - - if (_lastTypingEvent != null && - now.difference(_lastTypingEvent).inSeconds > 1) { - stopTyping(); - } - - state._clean(); - }); - } - - Timer _pinnedMessagesTimer; - void _startCleaningPinnedMessages() { - _pinnedMessagesTimer = Timer.periodic(Duration(seconds: 30), (_) { - final now = DateTime.now(); - final expiredMessages = state.channelState.pinnedMessages - ?.where((m) => m.pinExpires?.isBefore(now) == true) - ?.toList() ?? - []; - if (expiredMessages.isNotEmpty) { - expiredMessages.forEach((m) => state.addMessage(m.copyWith( - pinExpires: null, - pinned: false, - pinnedAt: null, - pinnedBy: null, - ))); - - state._channelState = state._channelState.copyWith( - pinnedMessages: state.pinnedMessages.where(_pinIsValid()).toList(), - ); - } - }); - } - /// Call this method to dispose the channel client void dispose() { - _pinnedMessagesTimer.cancel(); - _cleaningTimer.cancel(); state.dispose(); } @@ -1281,6 +1233,10 @@ class ChannelClientState { _computeInitialUnread(); + _startCleaning(); + + _startCleaningPinnedMessages(); + _channel._client.chatPersistenceClient ?.getChannelThreads(_channel.cid) ?.then((threads) { @@ -1777,6 +1733,47 @@ class ChannelClientState { })); } + Timer _cleaningTimer; + void _startCleaning() { + if (_channel.config?.typingEvents == false) { + return; + } + + _cleaningTimer = Timer.periodic(Duration(seconds: 1), (_) { + final now = DateTime.now(); + + if (_channel._lastTypingEvent != null && + now.difference(_channel._lastTypingEvent).inSeconds > 1) { + _channel.stopTyping(); + } + + _clean(); + }); + } + + Timer _pinnedMessagesTimer; + void _startCleaningPinnedMessages() { + _pinnedMessagesTimer = Timer.periodic(Duration(seconds: 30), (_) { + final now = DateTime.now(); + final expiredMessages = channelState.pinnedMessages + ?.where((m) => m.pinExpires?.isBefore(now) == true) + ?.toList() ?? + []; + if (expiredMessages.isNotEmpty) { + expiredMessages.forEach((m) => addMessage(m.copyWith( + pinExpires: null, + pinned: false, + pinnedAt: null, + pinnedBy: null, + ))); + + _channelState = _channelState.copyWith( + pinnedMessages: pinnedMessages.where(_pinIsValid()).toList(), + ); + } + }); + } + void _clean() { final now = DateTime.now(); _typings.forEach((user, lastTypingEvent) { @@ -1800,6 +1797,8 @@ class ChannelClientState { _channelStateController.close(); _isUpToDateController.close(); _threadsController.close(); + _cleaningTimer.cancel(); + _pinnedMessagesTimer.cancel(); _typingEventsController.close(); } } From 36d0c74a0da2b3c6fbde35e63c9c865daf79d8d0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 24 Feb 2021 10:17:33 +0100 Subject: [PATCH 6/8] use updatechannelstate --- packages/stream_chat/lib/src/api/channel.dart | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 758d0317..a7231235 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -1655,6 +1655,7 @@ class ChannelClientState { watcherCount: updatedState.watcherCount, members: newMembers, read: newReads, + pinnedMessages: updatedState.pinnedMessages, ); } @@ -1755,21 +1756,24 @@ class ChannelClientState { void _startCleaningPinnedMessages() { _pinnedMessagesTimer = Timer.periodic(Duration(seconds: 30), (_) { final now = DateTime.now(); - final expiredMessages = channelState.pinnedMessages + var expiredMessages = channelState.pinnedMessages ?.where((m) => m.pinExpires?.isBefore(now) == true) ?.toList() ?? []; if (expiredMessages.isNotEmpty) { - expiredMessages.forEach((m) => addMessage(m.copyWith( - pinExpires: null, - pinned: false, - pinnedAt: null, - pinnedBy: null, - ))); + expiredMessages = expiredMessages + .map((m) => m.copyWith( + pinExpires: null, + pinned: false, + pinnedAt: null, + pinnedBy: null, + )) + .toList(); - _channelState = _channelState.copyWith( + updateChannelState(_channelState.copyWith( pinnedMessages: pinnedMessages.where(_pinIsValid()).toList(), - ); + messages: expiredMessages, + )); } }); } From 950a2347b23b57e14363bc24e880696fb6019dd9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 24 Feb 2021 10:17:44 +0100 Subject: [PATCH 7/8] update core readme --- .../example/lib/main.dart | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_persistence/example/lib/main.dart b/packages/stream_chat_persistence/example/lib/main.dart index b356d96b..6c614cc7 100644 --- a/packages/stream_chat_persistence/example/lib/main.dart +++ b/packages/stream_chat_persistence/example/lib/main.dart @@ -5,7 +5,10 @@ import 'package:stream_chat_persistence/stream_chat_persistence.dart'; Future main() async { /// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// project dashboard. - final client = StreamChatClient('b67pax5b2wdq'); + final client = StreamChatClient( + 'b67pax5b2wdq', + logLevel: Level.INFO, + ); WidgetsFlutterBinding.ensureInitialized(); @@ -175,6 +178,15 @@ class _MessageViewState extends State { Widget build(BuildContext context) { return Column( children: [ + StreamBuilder>( + initialData: widget.channel.state.pinnedMessages, + stream: widget.channel.state.pinnedMessagesStream, + builder: (context, snap) { + return Column( + children: snap.data?.map((p) => Text(p.text))?.toList() ?? [], + ); + }, + ), Expanded( child: ListView.builder( controller: _scrollController, @@ -183,11 +195,17 @@ class _MessageViewState extends State { itemBuilder: (BuildContext context, int index) { final item = _messages[index]; if (item.user.id == widget.channel.client.uid) { - return Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), + return GestureDetector( + onLongPress: () { + print('pinning'); + widget.channel.pinMessage(item, 120); + }, + child: Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), ), ); } else { From 925817383fbfa24ad0918d319be0c79b6a5a3ba7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 24 Feb 2021 10:48:04 +0100 Subject: [PATCH 8/8] fix example --- packages/stream_chat_flutter_core/README.md | 2 +- .../example/lib/main.dart | 30 ++++--------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md index d2443713..1fcf000b 100644 --- a/packages/stream_chat_flutter_core/README.md +++ b/packages/stream_chat_flutter_core/README.md @@ -3,7 +3,7 @@ > The official Flutter core components for Stream Chat, a service for > building chat applications. -[![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) +[![Pub](https://img.shields.io/pub/v/stream_chat_flutter_core.svg)](https://pub.dartlang.org/packages/stream_chat_flutter_core) ![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) [![Gitter](https://badges.gitter.im/GetStream/stream-chat-flutter.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) ![CI](https://github.com/GetStream/stream-chat-flutter/workflows/stream_flutter_workflow/badge.svg?branch=master) diff --git a/packages/stream_chat_persistence/example/lib/main.dart b/packages/stream_chat_persistence/example/lib/main.dart index 6c614cc7..b356d96b 100644 --- a/packages/stream_chat_persistence/example/lib/main.dart +++ b/packages/stream_chat_persistence/example/lib/main.dart @@ -5,10 +5,7 @@ import 'package:stream_chat_persistence/stream_chat_persistence.dart'; Future main() async { /// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// project dashboard. - final client = StreamChatClient( - 'b67pax5b2wdq', - logLevel: Level.INFO, - ); + final client = StreamChatClient('b67pax5b2wdq'); WidgetsFlutterBinding.ensureInitialized(); @@ -178,15 +175,6 @@ class _MessageViewState extends State { Widget build(BuildContext context) { return Column( children: [ - StreamBuilder>( - initialData: widget.channel.state.pinnedMessages, - stream: widget.channel.state.pinnedMessagesStream, - builder: (context, snap) { - return Column( - children: snap.data?.map((p) => Text(p.text))?.toList() ?? [], - ); - }, - ), Expanded( child: ListView.builder( controller: _scrollController, @@ -195,17 +183,11 @@ class _MessageViewState extends State { itemBuilder: (BuildContext context, int index) { final item = _messages[index]; if (item.user.id == widget.channel.client.uid) { - return GestureDetector( - onLongPress: () { - print('pinning'); - widget.channel.pinMessage(item, 120); - }, - child: Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), - ), + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), ), ); } else {