Merge pull request #275 from GetStream/pin-messages-offline-support
[Persistence] Add support for pinned messages
This commit is contained in:
@@ -40,8 +40,6 @@ class Channel {
|
||||
|
||||
state = ChannelClientState(this, channelState);
|
||||
_initializedCompleter.complete(true);
|
||||
_startCleaning();
|
||||
|
||||
_client.logger.info('New Channel instance initialized created');
|
||||
}
|
||||
|
||||
@@ -844,7 +842,6 @@ class Channel {
|
||||
if (!_initializedCompleter.isCompleted) {
|
||||
_initializedCompleter.complete(true);
|
||||
}
|
||||
_startCleaning();
|
||||
}
|
||||
|
||||
/// Stop watching the channel
|
||||
@@ -1184,28 +1181,8 @@ class Channel {
|
||||
));
|
||||
}
|
||||
|
||||
Timer _cleaningTimer;
|
||||
|
||||
void _startCleaning() {
|
||||
if (config?.typingEvents == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleaningTimer = Timer.periodic(Duration(milliseconds: 500), (_) {
|
||||
final now = DateTime.now();
|
||||
|
||||
if (_lastTypingEvent != null &&
|
||||
now.difference(_lastTypingEvent).inSeconds > 1) {
|
||||
stopTyping();
|
||||
}
|
||||
|
||||
state._clean();
|
||||
});
|
||||
}
|
||||
|
||||
/// Call this method to dispose the channel client
|
||||
void dispose() {
|
||||
_cleaningTimer.cancel();
|
||||
state.dispose();
|
||||
}
|
||||
|
||||
@@ -1256,6 +1233,10 @@ class ChannelClientState {
|
||||
|
||||
_computeInitialUnread();
|
||||
|
||||
_startCleaning();
|
||||
|
||||
_startCleaningPinnedMessages();
|
||||
|
||||
_channel._client.chatPersistenceClient
|
||||
?.getChannelThreads(_channel.cid)
|
||||
?.then((threads) {
|
||||
@@ -1413,6 +1394,15 @@ class ChannelClientState {
|
||||
..removeWhere((it) => it.userId != userId),
|
||||
);
|
||||
addMessage(message);
|
||||
|
||||
if (message.pinned == true) {
|
||||
_channelState = _channelState.copyWith(
|
||||
pinnedMessages: [
|
||||
..._channelState.pinnedMessages ?? [],
|
||||
message,
|
||||
],
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1502,6 +1492,13 @@ class ChannelClientState {
|
||||
Stream<List<Message>> get messagesStream =>
|
||||
channelStateStream.map((cs) => cs.messages);
|
||||
|
||||
/// Channel pinned message list
|
||||
List<Message> get pinnedMessages => _channelState.pinnedMessages?.toList();
|
||||
|
||||
/// Channel pinned message list as a stream
|
||||
Stream<List<Message>> get pinnedMessagesStream =>
|
||||
channelStateStream.map((cs) => cs.pinnedMessages?.toList());
|
||||
|
||||
/// Get channel last message
|
||||
Message get lastMessage => _channelState.messages?.isNotEmpty == true
|
||||
? _channelState.messages.last
|
||||
@@ -1658,6 +1655,7 @@ class ChannelClientState {
|
||||
watcherCount: updatedState.watcherCount,
|
||||
members: newMembers,
|
||||
read: newReads,
|
||||
pinnedMessages: updatedState.pinnedMessages,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1736,6 +1734,50 @@ 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();
|
||||
var expiredMessages = channelState.pinnedMessages
|
||||
?.where((m) => m.pinExpires?.isBefore(now) == true)
|
||||
?.toList() ??
|
||||
[];
|
||||
if (expiredMessages.isNotEmpty) {
|
||||
expiredMessages = expiredMessages
|
||||
.map((m) => m.copyWith(
|
||||
pinExpires: null,
|
||||
pinned: false,
|
||||
pinnedAt: null,
|
||||
pinnedBy: null,
|
||||
))
|
||||
.toList();
|
||||
|
||||
updateChannelState(_channelState.copyWith(
|
||||
pinnedMessages: pinnedMessages.where(_pinIsValid()).toList(),
|
||||
messages: expiredMessages,
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _clean() {
|
||||
final now = DateTime.now();
|
||||
_typings.forEach((user, lastTypingEvent) {
|
||||
@@ -1759,6 +1801,13 @@ class ChannelClientState {
|
||||
_channelStateController.close();
|
||||
_isUpToDateController.close();
|
||||
_threadsController.close();
|
||||
_cleaningTimer.cancel();
|
||||
_pinnedMessagesTimer.cancel();
|
||||
_typingEventsController.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool Function(Message) _pinIsValid() {
|
||||
final now = DateTime.now();
|
||||
return (Message m) => m.pinExpires.isAfter(now);
|
||||
}
|
||||
|
||||
@@ -56,10 +56,17 @@ abstract class ChatPersistenceClient {
|
||||
PaginationParams messagePagination,
|
||||
});
|
||||
|
||||
/// Get stored pinned [Message]s by providing channel [cid]
|
||||
Future<List<Message>> getPinnedMessagesByCid(
|
||||
String cid, {
|
||||
PaginationParams messagePagination,
|
||||
});
|
||||
|
||||
/// Get [ChannelState] data by providing channel [cid]
|
||||
Future<ChannelState> 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<void> deletePinnedMessageById(String messageId) {
|
||||
return deletePinnedMessageByIds([messageId]);
|
||||
}
|
||||
|
||||
/// Remove a message by [messageIds]
|
||||
Future<void> deleteMessageByIds(List<String> messageIds);
|
||||
|
||||
/// Remove a pinned message by [messageIds]
|
||||
Future<void> deletePinnedMessageByIds(List<String> messageIds);
|
||||
|
||||
/// Remove a message by channel [cid]
|
||||
Future<void> deleteMessageByCid(String cid) {
|
||||
return deleteMessageByCids([cid]);
|
||||
}
|
||||
|
||||
/// Remove a pinned message by channel [cid]
|
||||
Future<void> deletePinnedMessageByCid(String cid) {
|
||||
return deletePinnedMessageByCids([cid]);
|
||||
}
|
||||
|
||||
/// Remove a message by message [cids]
|
||||
Future<void> deleteMessageByCids(List<String> cids);
|
||||
|
||||
/// Remove a pinned message by message [cids]
|
||||
Future<void> deletePinnedMessageByCids(List<String> cids);
|
||||
|
||||
/// Remove a channel by [cid]
|
||||
Future<void> deleteChannels(List<String> cids);
|
||||
|
||||
@@ -119,6 +147,10 @@ abstract class ChatPersistenceClient {
|
||||
/// the new [messages] data
|
||||
Future<void> updateMessages(String cid, List<Message> messages);
|
||||
|
||||
/// Updates the pinned message data of a particular channel [cid] with
|
||||
/// the new [messages] data
|
||||
Future<void> updatePinnedMessages(String cid, List<Message> messages);
|
||||
|
||||
/// Returns all the threads by parent message of a particular channel by
|
||||
/// providing channel [cid]
|
||||
Future<Map<String, List<Message>>> 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)),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> The official Flutter core components for Stream Chat, a service for
|
||||
> building chat applications.
|
||||
|
||||
[](https://pub.dartlang.org/packages/stream_chat_flutter)
|
||||
[](https://pub.dartlang.org/packages/stream_chat_flutter_core)
|
||||

|
||||
[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||

|
||||
|
||||
@@ -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 = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
/* 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 = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
8559384DCD98ED6067CEF8CB /* Pods */,
|
||||
04AAB960E493BD92262BBF82 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
/* 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 = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* 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 */;
|
||||
}
|
||||
+3
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -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: ../
|
||||
|
||||
|
||||
@@ -101,12 +101,14 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
|
||||
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();
|
||||
}));
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -17,6 +17,10 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
|
||||
|
||||
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<MoorChatDatabase>
|
||||
}
|
||||
|
||||
Future<Message> _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<MoorChatDatabase>
|
||||
}
|
||||
return msgEntity.toMessage(
|
||||
user: userEntity?.toUser(),
|
||||
pinnedBy: pinnedByEntity?.toUser(),
|
||||
latestReactions: latestReactions,
|
||||
ownReactions: ownReactions,
|
||||
quotedMessage: quotedMessage,
|
||||
@@ -56,7 +62,9 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
|
||||
/// Returns a single message by matching the [Messages.id] with [id]
|
||||
Future<Message> 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<MoorChatDatabase>
|
||||
/// [Messages.channelCid] with [cid]
|
||||
Future<List<Message>> 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<MoorChatDatabase>
|
||||
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<MoorChatDatabase>
|
||||
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(
|
||||
|
||||
@@ -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<MoorChatDatabase>
|
||||
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<void> deleteMessageByIds(List<String> 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<void> deleteMessageByCids(List<String> cids) async {
|
||||
return (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids)))
|
||||
.go();
|
||||
}
|
||||
|
||||
Future<Message> _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<Message> 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<List<Message>> 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<List<Message>> 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<List<Message>> 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<void> updateMessages(String cid, List<Message> messageList) async {
|
||||
if (messageList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
return batch((batch) {
|
||||
batch.insertAll(
|
||||
pinnedMessages,
|
||||
messageList.map((it) => it.toPinnedEntity(cid: cid)).toList(),
|
||||
mode: InsertMode.insertOrReplace,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'pinned_message_dao.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// DaoGenerator
|
||||
// **************************************************************************
|
||||
|
||||
mixin _$PinnedMessageDaoMixin on DatabaseAccessor<MoorChatDatabase> {
|
||||
$PinnedMessagesTable get pinnedMessages => attachedDatabase.pinnedMessages;
|
||||
$UsersTable get users => attachedDatabase.users;
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
export 'channels.dart';
|
||||
export 'messages.dart';
|
||||
export 'pinned_messages.dart';
|
||||
export 'reactions.dart';
|
||||
export 'users.dart';
|
||||
export 'members.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')();
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'package:moor/moor.dart';
|
||||
|
||||
import 'messages.dart';
|
||||
|
||||
/// Represents a [PinnedMessages] table in [MoorChatDatabase].
|
||||
@DataClassName('PinnedMessageEntity')
|
||||
class PinnedMessages extends Messages {}
|
||||
@@ -28,11 +28,13 @@ extension ChannelEntityX on ChannelEntity {
|
||||
List<Member> members,
|
||||
List<Read> reads,
|
||||
List<Message> messages,
|
||||
List<Message> pinnedMessages,
|
||||
}) {
|
||||
return ChannelState(
|
||||
members: members,
|
||||
read: reads,
|
||||
messages: messages,
|
||||
pinnedMessages: pinnedMessages,
|
||||
channel: toChannelModel(createdBy: createdBy),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -8,6 +8,7 @@ extension MessageEntityX on MessageEntity {
|
||||
/// Maps a [MessageEntity] into [Message]
|
||||
Message toMessage({
|
||||
User user,
|
||||
User pinnedBy,
|
||||
List<Reaction> latestReactions,
|
||||
List<Reaction> 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Reaction> latestReactions,
|
||||
List<Reaction> 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -81,11 +81,21 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
||||
return _db.messageDao.deleteMessageByIds(messageIds);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deletePinnedMessageByIds(List<String> messageIds) {
|
||||
return _db.pinnedMessageDao.deleteMessageByIds(messageIds);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteMessageByCids(List<String> cids) {
|
||||
return _db.messageDao.deleteMessageByCids(cids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deletePinnedMessageByCids(List<String> cids) {
|
||||
return _db.pinnedMessageDao.deleteMessageByCids(cids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Member>> getMembersByCid(String cid) {
|
||||
return _db.memberDao.getMembersByCid(cid);
|
||||
@@ -107,6 +117,17 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Message>> getPinnedMessagesByCid(
|
||||
String cid, {
|
||||
PaginationParams messagePagination,
|
||||
}) {
|
||||
return _db.pinnedMessageDao.getMessagesByCid(
|
||||
cid,
|
||||
messagePagination: messagePagination,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Read>> getReadsByCid(String cid) {
|
||||
return _db.readDao.getReadsByCid(cid);
|
||||
@@ -178,6 +199,11 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
||||
return _db.messageDao.updateMessages(cid, messages);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updatePinnedMessages(String cid, List<Message> messages) {
|
||||
return _db.pinnedMessageDao.updateMessages(cid, messages);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateReactions(List<Reaction> reactions) {
|
||||
return _db.reactionDao.updateReactions(reactions);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user