From abc2ce4ed5b55ad6ffbb9497a04224487cd221ba Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 14 Sep 2023 14:53:26 +0300 Subject: [PATCH 01/37] Content moderation for PII --- assets/images/chat/text_rule_create_en.png | Bin 0 -> 103537 bytes assets/images/chat/text_rule_test_en.png | Bin 32171 -> 72240 bytes .../chat-sdk/develop/_content-moderation.mdx | 27 +++++++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 assets/images/chat/text_rule_create_en.png diff --git a/assets/images/chat/text_rule_create_en.png b/assets/images/chat/text_rule_create_en.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed5477a8afd55845156a24858f5f0229b03287a GIT binary patch literal 103537 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

`nx_N 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 literal 32171 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

  • GjJrEqnnK=$77oaNFv+PQ{PjrH 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
  • When the moderation result is **Rejected**, you can set the action on the moderated message to one of the following options:
    • Blocks the message. Agora recommends using this setting for online messages after you fully test this moderation rule and ensure it suits your needs.
    • (Default) Sends the message. Agora recommends using this setting when you are testing this moderation rule and do not want this rule to affect online messages.
    • Replaces the message with \*\*\*.
  • When the moderation action fails (for example, the timeout period of the text audit interface is 200 milliseconds; if no result is returned within 200 milliseconds, this moderation action times out), the message processing policy can be set to one of the following options:
    • Blocks the message.
    • (Default) Sends the message.
    • If the action on the moderated message is set as **Blocks the message**, the `508, MESSAGE_EXTERNAL_LOGIC_BLOCKED` error is returned after the message is blocked. You can set whether to indicate this error in the application. If you choose to indicate this error in the application, a red exclamation mark is displayed before the blocked message.
  • | - | Rule | Sets the threshold for each moderation category. | - | User management | Imposes a penalty on users who reach the violation limit within a time period. The moderation penalties include the following: banning the user, forcing the user to go offline, or deleting the user. | + | Rule Name | The rule name. | + | Conversation Type | The moderation scope, which can be one of the following: a one-to-one chat, chat group or chat room, chat groups or chat rooms. If you set a rule for a specific chat group or room, the global moderation rules for chat groups and rooms are overwritten. | + | Enable | Determine whether to turn a rule on or off. | + | Message Handling |
    • When the moderation result is **Rejected**, you can set the action on the moderated message to one of the following options:
      • Blocks the message. Agora recommends using this setting for online messages after you fully test this moderation rule and ensure it suits your needs.
      • (Default) Sends the message. Agora recommends using this setting when you are testing this moderation rule and do not want this rule to affect online messages.
      • Replaces the message with \*\*\*.
    • When the moderation action fails (for example, the timeout period of the text audit interface is 200 milliseconds; if no result is returned within 200 milliseconds, this moderation action times out), the message processing policy can be set to one of the following options:
      • Blocks the message.
      • (Default) Sends the message.
      • If the action on the moderated message is set as **Blocks the message**, the `508, MESSAGE_EXTERNAL_LOGIC_BLOCKED` error is returned after the message is blocked. You can set whether to indicate this error in the application. If you choose to indicate this error in the application, a red exclamation mark is displayed before the blocked message.
    | + | Model Selection | Set whether to use AI alongside your keyword lists. + | Word Sensitivity | Set the threshold for each moderation category. | + | User management | Impose a penalty on users who reach the violation limit within a time period. The moderation penalties include the following: banning the user, forcing the user to go offline, or deleting the user. | 3. After creating a rule, you can **edit** or **delete** the rule: @@ -106,7 +107,7 @@ Taking a one-to-one chat text as an example, follow these steps to create a text 1. To enter the **Rule Test** page, in the left navigation menu, click **Project Management** > **Config** for the project that you want > **Config** of Chat > **Text Moderation** or **Image Moderation** > **Rule Test**, as shown in the following figure: - ![text_rule_test_en](/images/chat/text_rule_edit_en.png) + ![text_rule_test_en](/images/chat/text_rule_test_en.png) 2. Select a rule, fill in the text to moderate, and click **Check** to test the rule. The moderation result is displayed on the same page. From 9d35ebb2181cbe3f17a6af2e0e2ae30b28d559fd Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 14 Sep 2023 15:01:04 +0300 Subject: [PATCH 02/37] Image update --- assets/images/chat/text_rule_test_en.png | Bin 72240 -> 64731 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/images/chat/text_rule_test_en.png b/assets/images/chat/text_rule_test_en.png index a8790ec3eab03e67a916e774240322bb1e8e0c03..cf07b028280ace1263c949d2716f294f343ab42e 100644 GIT binary patch literal 64731 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 QJ>b`US(UrFw~f627q91wF#rGn literal 72240 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 From 914b28a9be59ee36361fc660cef3b878d83122b9 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Sun, 17 Sep 2023 16:21:07 +0300 Subject: [PATCH 03/37] Added message recall to features in Enable --- assets/images/chat/chat_feature_overview.png | Bin 0 -> 59809 bytes shared/chat-sdk/get-started/_enable.mdx | 6 ++---- 2 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 assets/images/chat/chat_feature_overview.png diff --git a/assets/images/chat/chat_feature_overview.png b/assets/images/chat/chat_feature_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..bf501704c9b2d4ab3ba7566adeef26c92e8ecdaf GIT binary patch literal 59809 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%0DevAKe&~G)Q3jHAftF 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%0DVe!{1@0VQa{o<$7O4s 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, make sure that you have the following: 1. Enable the advanced features based on your business requirements. - - - + ![](/images/chat/chat_feature_overview.png) For details about these advanced features, see the following: - Message Callback +- Message Recall - Message Thread - Reaction - Offline Message Push (Advanced) @@ -47,7 +46,6 @@ For details about these advanced features, see the following: - Translation - Moderation - ## Get Chat project information assigns the following information to each project that enables : From 6d12d32744eb9534125629e1e97d0b921f96c38c Mon Sep 17 00:00:00 2001 From: atovpeko Date: Sun, 17 Sep 2023 16:55:56 +0300 Subject: [PATCH 04/37] api part --- .../send-receive-messages/project-implementation/android.mdx | 2 +- .../send-receive-messages/project-implementation/flutter.mdx | 2 +- .../send-receive-messages/project-implementation/ios.mdx | 2 +- .../project-implementation/react-native.mdx | 4 +++- .../send-receive-messages/project-implementation/unity.mdx | 2 +- .../send-receive-messages/project-implementation/web.mdx | 2 +- .../send-receive-messages/project-implementation/windows.mdx | 2 +- shared/chat-sdk/restful-api/_message-management.mdx | 2 +- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index cd055828c..be00c4c99 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -67,7 +67,7 @@ ChatClient.getInstance().chatManager().removeMessageListener(msgListener); ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```java try { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 05877ff71..687acb11b 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -255,7 +255,7 @@ String? thumbnailLocalPath = imgBody.thumbnailLocalPath; ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```dart try { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 221c284c3..accbc0b39 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -68,7 +68,7 @@ When a message arrives, the recipient receives an `messagesDidReceive` callback. ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```objective-c [[AgoraChatClient sharedClient].chatManager recallMessageWithMessageId:@"messageId" completion:^(AgoraChatError *aError) { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index 3954757c1..c91e9e90e 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -185,7 +185,9 @@ ChatClient.getInstance().chatManager.removeMessageListener(listener); ChatClient.getInstance().chatManager.removeAllMessageListener(); ``` ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. + +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). + ```typescript ChatClient.getInstance() .chatManager.recallMessage(this.state.lastMessage.msgId) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index b0d8aa57c..0f6ef6969 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -59,7 +59,7 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```csharp // Call `RecallMessage` to recall the message. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index b0e84c945..0847eaf69 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -119,7 +119,7 @@ WebIM.conn.addEventHandler("eventName",{ ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```javascript /** diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index f430b902a..87f045219 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -59,7 +59,7 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); ### Recall a message -Two minutes after a user sends a message, this user can withdraw it. Contact support@agora.io if you want to adjust the time limit. +By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```csharp // Call `RecallMessage` to recall the message. diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index 6430a7114..982af0faf 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1442,7 +1442,7 @@ The fields of `bodies` for different message types vary: ## Recall a message -Once a message is sent, you can call this method to recall the message. The default time limit for recalling a message is two minutes. To adjust this limit, contact support@agora.io. +Once a message is sent, you can call this method to recall the message. The default time limit for recalling a message is two minutes. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../get-started/enable). For each App Key, the call frequency limit of this method is 100 per second. From 0b16cdce7cdb128c1c04be5229919ce3427e4868 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 21 Sep 2023 21:13:51 +0300 Subject: [PATCH 05/37] client api updates --- .../retrieve-messages/project-implementation/android.mdx | 6 +++++- .../retrieve-messages/project-implementation/flutter.mdx | 6 +++++- .../retrieve-messages/project-implementation/ios.mdx | 6 +++++- .../project-implementation/react-native.mdx | 8 ++++++-- .../retrieve-messages/project-implementation/unity.mdx | 8 ++++++-- .../retrieve-messages/project-implementation/web.mdx | 5 +++++ .../retrieve-messages/project-implementation/windows.mdx | 7 ++++++- 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index cf8102677..7eac09b6f 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -3,7 +3,7 @@ ## Retrieve a list of conversations from the server Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. ```java // pageNum: The current page number, starting from 1. @@ -29,6 +29,10 @@ After retrieving conversations, you can retrieve historical messages by paginati You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```java diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index 8ed004019..43b63c81a 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -3,7 +3,7 @@ ### Retrieve a list of conversations from the server Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. ```dart try { @@ -22,6 +22,10 @@ For users that do not support `fetchConversationListFromServer`, call `getConver After retrieving conversations, you can retrieve historical messages by pagination from the server. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```dart diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 8891b59b0..991a18b5c 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -3,7 +3,7 @@ ### Retrieve a list of conversations from the server Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. ```objective-c // pageNum: The current page number, starting from 1. @@ -21,6 +21,10 @@ After retrieving conversations, you can retrieve historical messages by paginati You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```objective-c diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 585751831..6d4c2524e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -3,7 +3,7 @@ ## Retrieve a list of conversations from the server Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. ```java // pageNum: The current page number, starting from 1. @@ -24,7 +24,11 @@ For users that do not support `fetchConversationsFromServerWithPage`, call `fetc After retrieving conversations, you can retrieve historical messages by pagination from the server. -To ensure data reliablity, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```typescript // Specify the conversation ID. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index 0620ddf9b..df6512480 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -3,7 +3,7 @@ ### Retrieve a list of conversations from the server Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. ```csharp SDKClient.Instance.ChatManager.GetConversationsFromServerWithPage(pageNum, pageSize, new ValueCallBack>( @@ -24,7 +24,11 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon After retrieving conversations, you can retrieve historical messages by pagination from the server. -To ensure data reliablity, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```csharp SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, type, startId, pageSize, new ValueCallBack>( diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index f68f030fa..abeda6d5e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -3,6 +3,7 @@ ## Retrieve a list of conversations from the server Call `getConversationlist` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +Agora Chat server can store up to 3,000 conversation per end user.

    Do not use mixed upper-case.
    @@ -20,6 +21,10 @@ After retrieving conversations, you can retrieve historical messages by paginati You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```javascript diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 5ca9c36aa..66c69ebc8 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -4,6 +4,7 @@ Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. +Agora Chat server can store up to 3,000 conversation per end user. ```csharp SDKClient.Instance.ChatManager.GetConversationsFromServerWithPage(pageNum, pageSize, new ValueCallBack>( @@ -24,7 +25,11 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon After retrieving conversations, you can retrieve historical messages by pagination from the server. -To ensure data reliablity, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. ```csharp SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, type, startId, pageSize, new ValueCallBack>( From 27c4e1744cbba471b10a7ba597ecde80bf1d251a Mon Sep 17 00:00:00 2001 From: Saud <65331551+saudsami@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:13:18 +0500 Subject: [PATCH 06/37] Chat 1.2 updates 376 377 380 (#664) * Updates * Updates * Updates * Updates * Updates * fixed indentation * member attributes code * update * restful-api-updates * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/messages/_send-receive-messages.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> * Update shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> --------- Co-authored-by: atovpeko <114177030+atovpeko@users.noreply.github.com> --- .../project-implementation/android.mdx | 106 ++++++++ .../project-implementation/flutter.mdx | 46 +++- .../project-implementation/ios.mdx | 30 +++ .../project-implementation/react-native.mdx | 55 +++- .../project-implementation/unity.mdx | 66 ++++- .../project-implementation/web.mdx | 46 +++- .../project-implementation/windows.mdx | 68 ++++- .../messages/_send-receive-messages.mdx | 34 ++- .../project-implementation/android.mdx | 76 ++++++ .../project-implementation/flutter.mdx | 53 ++++ .../project-implementation/ios.mdx | 48 ++++ .../project-implementation/react-native.mdx | 67 +++++ .../project-implementation/unity.mdx | 77 ++++++ .../project-implementation/web.mdx | 85 ++++++ .../project-implementation/windows.mdx | 77 ++++++ shared/chat-sdk/reference/_limitations.mdx | 19 ++ .../_manage-group-members.mdx | 254 ++++++++++++++++-- 17 files changed, 1176 insertions(+), 31 deletions(-) diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx index e168cb860..05e2bce55 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx @@ -128,6 +128,112 @@ public void checkIfInGroupWhiteList(final String groupId, ValueCallBack public void fetchGroupWhiteList(final String groupId, final ValueCallBack> callBack); ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```java + Map attributeMap = new HashMap<>(); + attributeMap.put("nickName", nickName); + + ChatClient.getInstance().groupManager().asyncSetGroupMemberAttributes( + groupId, + userId, + attributeMap, + new CallBack() { + @Override + public void onSuccess() { + // Indent content inside the method + } + + @Override + public void onError(int code, String error) { + // Indent content inside the method + } + } + ); + ``` + +1. Retrieve all attributes of a group member: + + ```java + ChatClient.getInstance().groupManager().asyncFetchGroupMemberAllAttributes( + groupId, + userId, + new ValueCallBack>>() { + @Override + public void onSuccess(Map> value) { + if (value != null) { + Map attributeMap = value.get(userId); + } + } + + @Override + public void onError(int code, String error) { + } + } + ); + ``` + +1. Retrieve selected attributes of specific group members: + + ```java + List keyList = new ArrayList<>(); + keyList.add("nickName"); + + List userIds = new ArrayList<>(); + userIds.add("Tom"); + userIds.add("Jack"); + + ChatClient.getInstance().groupManager().asyncFetchGroupMembersAttributes( + groupId, + userIds, + keyList, + new ValueCallBack>>() { + @Override + public void onSuccess(Map> value) { + if (value != null) { + for (String user : userIds) { + Map map = value.get(user); + if (map != null) { + //…… + } + } + } + } + + @Override + public void onError(int code, String error) { + } + } + ); + ``` + +1. Receive notification of changes in group member attributes: + + ```java + // Create a GroupChangeListener object + GroupChangeListener groupChangeListener = new GroupChangeListener() { + // …… + + @Override + public void onGroupMemberAttributeChanged(String groupId, String userId, Map attribute, String from) { + if (attribute != null && attribute.size() > 0) { + // EMLog.d(TAG,"onGroupMemberAttributeChanged: " + groupId +" - "+ attribute.toString()); + } + } + }; + + // Add a group change listener: + ChatClient.getInstance().groupManager().addGroupChangeListener(groupChangeListener); + + // Remove a group change listener: + ChatClient.getInstance().groupManager().removeGroupChangeListener(groupChangeListener); + + ``` + ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx index dfdedbbda..a65c450ba 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx @@ -260,8 +260,52 @@ try { } ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```dart + await ChatClient.getInstance.groupManager.setMemberAttributes( + groupId: groupId, + userId: userId, + attributes: {'key': 'value'}, + ); + ``` + +1. Retrieve attributes of group members: + + ```dart + Map attribute = + await ChatClient.getInstance.groupManager.fetchMemberAttributes( + groupId: 'groupId', + userId: 'userId', + ); + ``` + + +1. Receive notification of changes in group member attributes: + + ```dart + // Add an event handler + ChatClient.getInstance.groupManager.addEventHandler( + 'UNIQUE_HANDLER_ID', + ChatGroupEventHandler( + onAttributesChangedOfGroupMember: + (groupId, userId, attributes, operatorId) {}, + ), + ); + + // ... + + // Remove an event handler + ChatClient.getInstance.groupManager.removeEventHandler('UNIQUE_HANDLER_ID'); + ``` + + ### Listen for chat group events -For details, see [Chat Group Events]./manage-chat-groups#listen-for-chat-group-events). +For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx index 9421e18e7..faafcf87a 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx @@ -160,6 +160,36 @@ Refer to the following sample code to manage the chat group allow list: [[AgoraChatClient sharedClient].groupManager getGroupWhiteListFromServerWithId:@"groupID" error:nil]; ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```objective-c + [AgoraChatClient.sharedClient.groupManager setMemberAttribute:@"groupId" + userId:@"userId" + attributes:@{@"key":@"value"} + completion:^(AgoraChatError * _Nullable error) { + }]; + ``` + +1. Retrieve attributes of group members: + + ```objective-c + [AgoraChatClient.sharedClient.groupManager fetchMembersAttributes:@"groupId" userIds:@[@"userId1",@"userId2"] keys:@[@"key1",@"key2"] completion:^(NSDictionary *> * _Nullable attributes, AgoraChatError * _Nullable error) { + + }]; + ``` + + +1. Receive notification of changes in group member attributes: + + ```objective-c + - (void)onAttributesChangedOfGroupMember:(NSString *)groupId userId:(NSString *)userId attributes:(NSDictionary *)attributes operatorId:(NSString *)operatorId { + } + ``` + ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx index 96085ae8b..45fdfb1ed 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx @@ -302,8 +302,61 @@ ChatClient.getInstance() }); ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```typescript + // groupId: The group ID. + // member: The user ID of the group member. + // attributes: The custom attributes to set. + ChatClient.getInstance() + .groupManager.setMemberAttribute(groupId, member, attributes) + .then(() => { + console.log("set group members attributes success."); + }) + .catch((reason) => { + console.log("set group members attributes fail.", reason); + }); + + ``` + +1. Retrieve attributes of group members: + + ```typescript + // groupId: The group ID. + // member: The user ID of the group member. + ChatClient.getInstance() + .groupManager.fetchMemberAttributes(groupId, member) + .then((attributes: Record | undefined) => { + console.log("get group members attributes success.", attributes); + }) + .catch((reason) => { + console.log("get group members attributes fail.", reason); + }); + ``` + + +1. Receive notification of changes in group member attributes: + + ```typescript + onMemberAttributesChanged(params: { + groupId: string; + member: string; + attributes: any; + operator: string; + }): void { + console.log(`${QuickTestScreenBase.TAG}: onStateChanged:`, params); + this.that.setState({ + recvResult: `onMemberAttributesChanged: ` + params, + }); + } + ``` + ### Listen for chat group events -For details, see [Chat Group Events]./manage-chat-groups#listen-for-chat-group-events). +For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx index 81c06505b..bb894b37b 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx @@ -292,8 +292,72 @@ SDKClient.Instance.GroupManager.GetGroupWhiteListFromServer(currentGroupId, call )); ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```csharp + Dictionary dict = new Dictionary(); + dict.Add("key", "value"); + + SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( + onSuccess: () => + { + Console.WriteLine($"SetMemberAttributes success."); + }, + onError: (code, desc) => + { + Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); + } + )); + + ``` + +1. Retrieve attributes of group members: + + ```csharp + List userList = new List(); + userList.Add("user"); + + // keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. + List keyList = new List(); + keyList.Add("key"); + + SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( + onSuccess: (dict) => + { + + }, + onError: (code, desc) => + { + + } + )); + ``` + +1. Receive notification of changes in group member attributes: + + ```csharp + // Inherit and implement `IGroupManagerDelegate`. + public class GroupManagerDelegate : IGroupManagerDelegate { + + public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) + { + } + } + + // Add a delegate. + GroupManagerDelegate adelegate = new GroupManagerDelegate(); + SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); + + // Remove the delegate when it is unnecessary. + SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); + ``` + ### Listen for chat group events -For details, see [Chat Group Events]./manage-chat-groups#listen-for-chat-group-events). +For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx index eeb9c2aeb..570f30b89 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx @@ -195,8 +195,52 @@ let options = { conn.getGroupAllowlist(options).then(res => console.log(res)); ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```js + let options = { + groupId: 'groupId', + userId: 'userId', + memberAttributes: { + key: 'value' + }, + } + + connection.setGroupMemberAttributes(options).then((res) => { + console.log(res) + }).catch((e) => { + console.log(e) + }) + ``` + +1. Retrieve attributes of group members: + + ```js + let options = { + groupId: 'groupId', + userId: 'userId' + } + + connection.getGroupMemberAttributes(options).then((res) => { + console.log(res) + }).catch((e) => { + console.log(e) + }) + ``` + +1. Receive notification of changes in group member attributes: + + ```js + case "memberAttributesUpdate": + break; + ``` + ### Listen for chat group events -For details, see [Chat Group Events]./manage-chat-groups#listen-for-chat-group-events). +For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx index 6dc4af3e8..d3f48b4ea 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx @@ -292,8 +292,74 @@ SDKClient.Instance.GroupManager.GetGroupWhiteListFromServer(currentGroupId, call )); ``` +### Manage custom attributes of group members + +Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. + +1. Set group member attributes: + + ```csharp + Dictionary dict = new Dictionary(); + dict.Add("key", "value"); + + SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( + onSuccess: () => + { + Console.WriteLine($"SetMemberAttributes success."); + }, + onError: (code, desc) => + { + Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); + } + )); + + ``` + +1. Retrieve attributes of group members: + + ```csharp + List userList = new List(); + userList.Add("user"); + + // keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. + List keyList = new List(); + keyList.Add("key"); + + SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( + onSuccess: (dict) => + { + + }, + onError: (code, desc) => + { + + } + )); + ``` + +1. Receive notification of changes in group member attributes: + + ```csharp + // Inherit and implement `IGroupManagerDelegate` + public class GroupManagerDelegate : IGroupManagerDelegate { + + public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) + { + + } + } + + // Add a delegate + GroupManagerDelegate adelegate = new GroupManagerDelegate(); + SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); + + // Remove the delegate when it is no longer required + SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); + ``` + + ### Listen for chat group events -For details, see [Chat Group Events]./manage-chat-groups#listen-for-chat-group-events). +For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx index fbd1a29c5..51daab90e 100644 --- a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx +++ b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx @@ -4,30 +4,50 @@ import ProjectImplement from '@docs/shared/chat-sdk/client-api/messages/send-rec After logging in to Chat, users can send the following types of messages to a peer user, a chat group, or a chat room: -- Text messages, including hyperlinks and emojis. +- Text messages, including hyperlinks and emojis. - Attachment messages, including image, voice, video, and file messages. - - Location messages. - - CMD messages. - - Extended messages. - - Custom messages. The Chat message feature is language agnostic. End users can send messages in any language, as long as their devices support input in that language. -This page shows how to implement sending and receiving these messages using the Chat SDK. +In addition to sending messages, users can also forward one or more messages. When forwarding multiple messages, users have the following options: + +* Forward messages one-by-one +* Forward consolidated messages as message history + +This page shows how to implement sending, receiving, forwarding multiple messages, and modifying sent messages using the . ## Understand the tech +**Forward multiple messages​** + + provides client APIs for forwarding multiple messages. Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. When a user receives a consolidated message with multiple forwarded messages, they can forward this message again, thus creating a layered message. This action can be performed up to 10 times. For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +**Modify sent messages​** + + provides client APIs that enable end users to edit messages after sending. Every end user or chat group member may edit messages that they have sent. The original message is recalled and a new messages is sent after editing. Once a message is recalled, it is purged from the message history stored on Agora's Chat servers. An edited message contains the following information: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was recalled and edited. +* The number of times a recalled message was edited (up to 5 times). +* The content of the most recent message. + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). + + ## Prerequisites Before proceeding, ensure that you meet the following requirements: -- You have integrated the Chat SDK, initialized the SDK and implemented the functionality of registering accounts and login. For details, see Chat . +- You have integrated the Chat SDK, initialized the SDK, and implemented the functionality of registering accounts and login. For details, see Chat . + + Use 1.2 or higher if you intend to enable users to forward multiple messages, or to modify sent messages. + - You understand the API call frequency limits as described in [Limitations](/agora-chat/reference/limitations). ## Implementation diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index be00c4c99..6c9151641 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -336,4 +336,80 @@ ChatClient.getInstance().chatManager().sendMessage(message); message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attribute2", false) ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```java + ChatMessage message = ChatMessage.createCombinedSendMessage(title, summary, compatibleText, msgIds, toChatUsername); + // Set the chat type: + // One-to-one chat: ChatMessage.ChatType.Chat + // Group chat: ChatMessage.GroupChat + // Room chat: ChatMessage.ChatRoom + message.setChatType(ChatMessage.ChatType.Chat); + // Send the message + ChatClient.getInstance().chatManager().sendMessage(message); + ``` + +2. Download and parse combined messages: + + ```java + ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { + @Override + public void onSuccess(List value) { + + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `asyncModifyMessage` with the message ID and the new message body: + + ```java + String newContent="new content"; + TextMessageBody newTextMessageBody = new TextMessageBody(newContent); + ChatClient.getInstance().chatManager().asyncModifyMessage(targetMessage.getMsgId(), newTextMessageBody, new ValueCallBack() { + @Override + public void onSuccess(ChatMessage value) { + + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); + ``` + +1. Receive notification of messages modified by other users: + + ```java + // Create a MessageListener object + MessageListener messageListener = new MessageListener() { + //…… + + @Override + public void onMessageContentChanged(ChatMessage messageModified, String operatorId, long operationTime) { + // int operationCount = messageModified.getBody().operationCount(); + // operatorId and operationTime can also be obtained as follows: + // String id = messageModified.getBody().operatorId(); + // long time = messageModified.getBody().operationTime(); + } + }; + // Register the messageListener + ChatClient.getInstance().chatManager().addMessageListener(messageListener); + // Remove the messageListener + ChatClient.getInstance().chatManager().removeMessageListener(messageListener); + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 687acb11b..e8b5c3011 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -274,4 +274,57 @@ ChatClient.getInstance.chatManager.addEventHandler( ); ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```dart + String title = "Historical messages for one-to-one chats between A and B"; + String summary = + "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = + "Your current version does not support this type of message. Please upgrade to the latest version."; + final msg = ChatMessage.createCombineSendMessage( + targetId: targetId, + msgIds: msgIds, + title: title, + summary: summary, + compatibleText: compatibleText, + ); + await ChatClient.getInstance.chatManager.sendMessage(msg); + ``` + +2. Download and parse combined messages: + + ```dart + List list = + await ChatClient.getInstance.chatManager.fetchCombineMessageDetail( + message: combineMessage, + ); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `modifyMessage` with the message ID and the new message body: + + ```dart + ChatTextMessageBody body = ChatTextMessageBody(content: "new content"); + await ChatClient.getInstance.chatManager.modifyMessage( + messageId: msgId, + msgBody: body, + ); + ``` + +1. Receive notification of messages modified by other users: + + ```dart + ChatEventHandler( + onMessageContentChanged: (message, operatorId, operationTime) {}, + ) + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index accbc0b39..9b4842309 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -356,4 +356,52 @@ message.chatType = AgoraChatTypeChat; } ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```objective-c + AgoraChatCombineMessageBody *body = [[AgoraChatCombineMessageBody alloc] initWithTitle:@"Chat History" summary:@"summary" compatibleText:@"The version is low and unable to display the content." messageIdList:@[@"messageId1",@"messageId2"]]; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:@"conversationId" body:body ext:nil]; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:^(AgoraChatMessage *aMessage, AgoraChatError *aError) { + }]; + ``` + +2. Download and parse combined messages: + + ```objective-c + - (void)messagesDidReceive:(NSArray *)aMessages + { + for(AgoraChatMessage* msg in aMessages) { + if (msg.body.type == AgoraChatMessageBodyTypeCombine) { + [AgoraChatClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, AgoraChatError * _Nullable error) { + + }]; + } + } + } + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `modifyMessage` with the message ID and the new message body: + + ```objective-c + AgoraChatTextMessageBody* newBody = [[AgoraChatTextMessageBody alloc] initWithText:@"new content"]; + [AgoraChatClient.sharedClient.chatManager modifyMessage:msgId body:newBody completion:^(AgoraChatError * _Nullable error, AgoraChatMessage * _Nullable message) { + + }]; + ``` + +1. Receive notification of messages modified by other users: + + ```objective-c + - (void)onMessageContentChanged:(AgoraChatMessage *)message operatorId:(NSString *)operatorId operationTime:(NSUInteger)operationTime { + + } + ``` \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index c91e9e90e..7e8087be0 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -204,4 +204,71 @@ You can also use `ChatMessageEventListener` to listen for the state of recalling onMessagesRecalled(messages: ChatMessage[]): void; ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```typescript + // Construct a combined message. + const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { + title, + summary, + compatibleText, + }); + EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); + ``` + +2. Download and parse combined messages: + + ```typescript + // message: The combined message object. + // Asynchronously return the list of original messages. + ChatClient.getInstance() + .chatManager.fetchCombineMessageDetail(message) + .then((messages: ChatMessage[]) => { + console.log("success: ", messages); + }) + .catch((error) => { + console.log("fail: ", error); + }); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `modifyMessageBody` with the message ID and the new message body: + + ```typescript + ChatClient.getInstance() + .chatManager.modifyMessageBody(msgId, body) + .then((message) => { + console.log("modify success:", message); + }) + .catch((error) => { + console.warn(error); + }); + ``` + +1. Receive notification of messages modified by other users: + + ```typescript + ChatClient.getInstance().chatManager.addMessageListener({ + onMessageContentChanged: ( + message: ChatMessage, + lastModifyOperatorId: string, + lastModifyTime: number + ): void => { + console.log( + `${QuickTestScreenChat.TAG}: onMessageContentChanged: `, + JSON.stringify(message), + lastModifyOperatorId, + lastModifyTime + ); + }, + } as ChatMessageEventListener); + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 0f6ef6969..ce45f88e2 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -398,4 +398,81 @@ if (found) { } ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```csharp + String title = "Historical messages for one-to-one chats between A and B"; + String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; + Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); + + SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + // Handling logic upon sending success + }, + onError: (code, desc) => { + // Handling logic if sendMessage fails + } + )); + ``` + +2. Download and parse combined messages: + + ```csharp + SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // Add the handling logic and show the message list + }, + onError: (code, desc) => { + // Handle an error + } + )); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `ModifyMessage` with the message ID and the new message body: + + ```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) => + { + + }, + onError: (code, desc) => + { + + } + )); + ``` + +1. Receive notification of messages modified by other users: + + ```csharp + // Inherit and implement `IChatManagerDelegate`. + public class ChatManagerDelegate : IChatManagerDelegate { + + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime as follows: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + + // Add a delegate. + ChatManagerDelegate adelegate = new ChatManagerDelegate(); + SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + + // Remove the delegate when it is no longer required + SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 0847eaf69..ced5ff563 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -494,4 +494,89 @@ function sendPrivateText() { } ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```javascript + let option = { + chatType: "singleChat", + type: "combine", + to: "userId", + compatibleText: "Your SDK does not support combined messages. Please upgrade.", + title: "Chat history", + summary: "hi", + messageList: [ + // message body + { + type: "txt", + chatType: "singleChat", + // ... + }, + ], + onFileUploadComplete: (data) => { + option.url = data.url; + }, + }; + let msg = AC.message.create(option); + connection.send + .send(msg) + .then((res) => { + console.log("Succeeded in sending the message", res); + }) + .catch((err) => { + console.log("Failed to send the message", err); + }); + + ``` + + +2. Download and parse combined messages: + + ```javascript + connection.downloadAndParseCombineMessage({ + url: msg.url, + secret: msg.secret, + }) + .then((res) => { + console.log("The list of original messages obtained after parsing", res); + }); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `modifyMessage` with the message ID and the new message body: + + ```javascript + const textMessage = AC.message.create({ + type: 'txt', + msg: 'message content', + to: 'username', + chatType: 'singleChat', + }); + + connection.modifyMessage({ messageId: 'messageId', modifiedMessage: textMessage }) + .then((res) => { + console.log(res.message) + }) + .catch((e) => { + console.log(e) + }); + ``` + +1. Receive notification of messages modified by other users: + + ```javascript + // Adds the message modification event + connection.addEventHandler("modifiedMessage", { + onModifiedMessage: message => { + console.log('onModifiedMessage', message) + }, + }); + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 87f045219..01574df4e 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -397,4 +397,81 @@ if (found) { // Use variable b. } ``` +### Forward multiple messages + +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```csharp + String title = "Historical messages for one-to-one chats between A and B"; + String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; + Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); + + SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + // Handling logic upon sending success + }, + onError: (code, desc) => { + // Handling logic if sendMessage fails + } + )); + ``` + +2. Download and parse combined messages: + + ```csharp + SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // Add the handling logic and show the message list + }, + onError: (code, desc) => { + // Handle an error + } + )); + ``` + +### Modify sent messages + +To modify a sent message, refer to the following code: + +1. Call `ModifyMessage` with the message ID and the new message body: + + ```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) => + { + + }, + onError: (code, desc) => + { + + } + )); + ``` + +1. Receive notification of messages modified by other users: + + ```csharp + // Inherit and implement `IChatManagerDelegate`. + public class ChatManagerDelegate : IChatManagerDelegate { + + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime as follows: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + + // Add a delegate. + ChatManagerDelegate adelegate = new ChatManagerDelegate(); + SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + + // Remove the delegate when it is no longer required. + SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); + ``` + \ No newline at end of file diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index 6c5d79f64..d31f24b75 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -49,6 +49,25 @@ Each chat room can have up to 100 custom attributes, and the total size of chat - 10 numbers 0 -9; - "_", "-", ".". +### Multiple messages forwarding limitations + + +* The forwarding multiple messages​ capability is available only in client APIs and not RESTful APIs. +* End users can only forward up to 300 messages at a time. +* The content of the forwarded messages can't be searched. +* When forwarding multiple messages in a consolidated form, the title and preview of the combined message is displayed. The content of the message preview can't exceed 5KB. +* Applications developed with versions prioir to `1.2.x`` will not support display of forwarded messages. + +### Sent message modification limitations + +This feature has the following limitations: + +* End users can only edit messages sent by themselves and not others. +* Supported message types: text only. +* Supported use case: 1:1 & chat group. Do not support Chatroom. +* End users can recall and edit messages that were sent up to 7 days ago. +* We support editing the same message for up to 5 times. + ### RESTful API Call limit of server-side The RESTful API call frequency limit of each method varies. For details about each method, see [**Chat RESTful API Reference**](https://docs.agora.io/en/agora-chat/restful-api/restful-overview). diff --git a/shared/chat-sdk/restful-api/chat-group-management/_manage-group-members.mdx b/shared/chat-sdk/restful-api/chat-group-management/_manage-group-members.mdx index 8acd23f29..6adffb80d 100644 --- a/shared/chat-sdk/restful-api/chat-group-management/_manage-group-members.mdx +++ b/shared/chat-sdk/restful-api/chat-group-management/_manage-group-members.mdx @@ -67,7 +67,7 @@ GET https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/users?pagenum={N} | `pagenum` | Number | The current page number. The query starts from the first page by default. | No | | `pagesize` | Number | The number of members to retrieve per page. The default value is 10. The value range is [1,100]. | No | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -87,7 +87,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `owner` | String | The username of the group owner, for example, `{"owner":"user1"}`. | | `member` | String | The username of group members, for example, `{"member":"user2"}`. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -147,7 +147,7 @@ POST https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/users/{username} | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request parameters @@ -170,7 +170,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `action` | String | The request method. | | `user` | String | The username added to the chat group. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -219,7 +219,7 @@ POST https://{host}/{org_name}/{app_name}/chatgroups/{chatgroupid}/users | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -247,7 +247,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `groupid` | String | The group ID. | | `action` | String | The request method. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -305,7 +305,7 @@ DELETE https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/users/{usernam | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -327,7 +327,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `action` | String | The request method. | | `user` | String | The usernames removed from the chat group. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -379,7 +379,7 @@ DELETE https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/users/{members | group_id | String | The group ID. | Yes | | members | String | The usernames of group members separated by the comma (,). For example, `user1, user2`. | Yes | -For the descriptions of other path parameters, see [Common Parameters](#param). +For the descriptions of other path parameters, see [Common Parameters](#common-parameters). #### Request header @@ -402,7 +402,7 @@ If the returned HTTP status code is 200, the request succeeds to and the `data` | `action` | String | The request method. | | `user` | String | The usernames removed from the chat group. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -448,6 +448,220 @@ curl -X DELETE -H 'Accept: application/json' -H 'Authorization: Bearer
  • The key indicates the attribute name and cannot exceed 16 bytes.
  • The value indicates the attribute value and cannot exceed 512 bytes. Passing an empty string to the value means to delete the attribute.
  • For a single group member, the total length of custom attributes cannot exceed 4 KB. | + +### HTTP response + +#### Response body + +If the returned HTTP status code is 200, the request succeeds and the response body contains the following parameters. + +| Field | Type | Description | +| :----- | :--- | :----------------------- | +| `data` | JSON | Custom attributes of a group member that are set. | + +For other fields and descriptions, see [Common parameters](#common-parameters). + +If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](https://docs.agora.io/en/agora-chat/reference/http-status-codes?platform=android) for possible causes. + +### Example + +#### Request example + +```shell +curl --location --request PUT 'https://XXXX/XXXX/XXXX/metadata/chatgroup/207059303858177/user/test2' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' +-H 'Authorization: Bearer ' \ +-d '{ + "metaData": { + "key1": "value1" + } +}' +``` + +#### Response example + +```json +{ + "timestamp": 1678674135533, + "data": { + "key1": "value1" + }, + "duration": 53 +} +``` + +## Retrieving all custom attributes of a group member + +Retrieves all custom attributes of a group member. + +### HTTP request + +```shell +GET https://{host}/{org_name}/{app_name}/metadata/chatgroup/{group_id}/user/{username} +``` + +#### Path parameter + +| Parameter | Type | Description | Required | +| :-------------- | :----- | :------- | :----------- | +| `username` | String | The user ID of a group member whose custom attributes are to be retrieved. | Yes | + +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). + +#### Request header + +| Parameter | Type | Description | Required | +| :-------------- | :----- | :------- | :----------- | +| `Content-Type` | String | The parameter type. Set it as `application/json`. | Yes | +| `Accept` | String | The parameter type. Set it as `application/json`.| Yes | +| `Authorization` | String | The authentication token of the user or administrator, in the format of `Bearer ${YourAppToken}`, where `Bearer` is a fixed character, followed by an English space, and then the obtained token value. | Yes | + +### HTTP response + +#### Response body + +If the returned HTTP status code is 200, the request succeeds and the response body will contain the following parameters. + +| Field | Type | Description | +| :----- | :--- | :----------------------- | +| `data` | JSON | All custom attributes of a group member that are retrieved. | + +For other fields and descriptions, see [Common parameters](#common-parameters). + +If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](https://docs.agora.io/en/agora-chat/reference/http-status-codes?platform=android) for possible causes. + +### Example + +#### Request example + +```shell +curl --location --request GET 'https://XXXX/XXXX/XXXX/metadata/chatgroup/207059303858177/user/test2' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' +-H 'Authorization: Bearer ' \ +-d '' +``` + +#### Response example + +```json +{ + "timestamp": 1678674211840, + "data": { + "key1": "value1" + }, + "duration": 6 +} +``` + +## Retrieving custom attributes of multiple group members by attribute key + +Retrieves custom attributes of multiple group members by attribute key. You can retrieve custom attributes of at most 10 group members each time. + +### HTTP request + +```shell +POST https://{host}/{org_name}/{app_name}/metadata/chatgroup/{group_id}/get +``` + +#### Path parameter + +For the parameters and detailed descriptions, see [Common parameters](#common-parameters). + +#### Request header + +| Parameter | Type | Description | Required | +| :-------------- | :----- | :------- | :----------- | +| `Content-Type` | String | The parameter type. Set it as `application/json`. | Yes | +| `Accept` | String | The parameter type. Set it as `application/json`.| Yes | +| `Authorization` | String | The authentication token of the user or administrator, in the format of `Bearer ${YourAppToken}`, where `Bearer` is a fixed character, followed by an English space, and then the obtained token value. | Yes | + +#### Request body + +| Parameter | Type | Description | Required | +| :----------- | :--------- | :------- | :------------- | +| `targets` | JSON Array | The user IDs of group members whose custom attributes are to be retrieved. You can pass in at most 10 user IDs. | Yes | +| `properties` | JSON Array | The array of keys of custom attributes to retrieve. If you pass in an empty string or no value to the parameter, all custom attributes of the group members will be returned. | Yes | + +### HTTP response + +#### Response body + +If the returned HTTP status code is 200, the request succeeds and the response body will contain the following parameters. + +| Field | Type | Description | +| :----- | :--- | :------------------------------------------------------------------------------------------------ | +| `data` | JSON | The custom attributes of the group members that are retrieved. As shown in the following response example, `test1` and `test2` are user IDs of group members to which the retrieved custom attributes belong. | + +For other fields and descriptions, see [Common parameters](#common-parameters). + +If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](https://docs.agora.io/en/agora-chat/reference/http-status-codes?platform=android) for possible causes. + +### Example + +#### Request example + +```shell +curl --location --request POST 'https://XXXX/XXXX/XXXX/metadata/chatgroup/207059303858177/get' \ +-H 'Content-Type: application/json' \ +-H 'Accept: application/json' +-H 'Authorization: Bearer ' \ +-d '{ + "targets":["test1","test2"], + "properties":["key1","key2"] +}' +``` + +#### Response example + +```json +{ + "timestamp": 1678674292783, + "data": { + "test1": { + "key1": "value1" + }, + "test2": { + "key1": "value1" + } + }, + "duration": 2 +} +``` ## Retrieving group admin list @@ -465,7 +679,7 @@ GET https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/admin | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -478,7 +692,7 @@ For other parameters and detailed descriptions, see [Common parameters](#param). #### Response body -If the returned HTTP status code is 200, the request succeeds, and the `data` field in the response body contain the information of the chat group admins. For other fields and descriptions, see [Common parameters](#param). +If the returned HTTP status code is 200, the request succeeds, and the `data` field in the response body contain the information of the chat group admins. For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -523,7 +737,7 @@ POST https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/admin | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -550,7 +764,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `data` | String | The user IDs promoted to group admins. | | `count` | Number | The number of users to be promoted as group admins. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -596,7 +810,7 @@ DELETE https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/admin | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -616,7 +830,7 @@ If the returned HTTP status code is 200, the request succeeds, and the `data` fi | `result` | Boolean | Whether the group admin is successfully demoted to a regular group member:
    • `true`: Yes.
    • `false`: No.
    | | `oldadmin` | String | The ID of the group admin demoted to a regular group member. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -663,7 +877,7 @@ PUT https://{host}/{org_name}/{app_name}/chatgroups/{group_id}/admin | :------- | :----- | :-------- | :------- | | `group_id` | String | The group ID. | Yes | -For other parameters and detailed descriptions, see [Common parameters](#param). +For other parameters and detailed descriptions, see [Common parameters](#common-parameters). #### Request header @@ -689,7 +903,7 @@ If the returned HTTP status code is 200, the request succeeds and the `data` fie | :------- | :------ | :---------------------------------------------- | | `newowner` | Boolean | Whether the user is successfully set as the chat group owner. true: Yes; false: No. | -For other fields and descriptions, see [Common parameters](#param). +For other fields and descriptions, see [Common parameters](#common-parameters). If the returned HTTP status code is not 200, the request fails. You can refer to [Status codes](#code) for possible causes. @@ -718,9 +932,11 @@ curl -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H "applicationName": "XXXX" } ``` -
    + + + ## Status codes For details, see [HTTP Status Codes](/agora-chat/reference/http-status-codes). \ No newline at end of file From 7352de53e73f83679b966e622d69699727e2f182 Mon Sep 17 00:00:00 2001 From: saudsami Date: Wed, 25 Oct 2023 11:27:53 +0500 Subject: [PATCH 07/37] review updates --- .../send-receive-messages/project-implementation/android.mdx | 2 +- .../send-receive-messages/project-implementation/flutter.mdx | 2 +- .../send-receive-messages/project-implementation/ios.mdx | 2 +- .../project-implementation/react-native.mdx | 2 +- .../send-receive-messages/project-implementation/unity.mdx | 2 +- .../send-receive-messages/project-implementation/web.mdx | 2 +- .../send-receive-messages/project-implementation/windows.mdx | 2 +- shared/chat-sdk/reference/_limitations.mdx | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 6c9151641..3d6380452 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -353,7 +353,7 @@ To forward and receive combined messages, refer to the following code: ChatClient.getInstance().chatManager().sendMessage(message); ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```java ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index e8b5c3011..55fefe8ff 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -296,7 +296,7 @@ To forward and receive combined messages, refer to the following code: await ChatClient.getInstance.chatManager.sendMessage(msg); ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```dart List list = diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 9b4842309..6527d39e8 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -369,7 +369,7 @@ To forward and receive combined messages, refer to the following code: }]; ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```objective-c - (void)messagesDidReceive:(NSArray *)aMessages diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index 7e8087be0..54e808f19 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -220,7 +220,7 @@ To forward and receive combined messages, refer to the following code: EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```typescript // message: The combined message object. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index ce45f88e2..20726cc16 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -420,7 +420,7 @@ To forward and receive combined messages, refer to the following code: )); ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```csharp SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index ced5ff563..aac5fb97f 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -533,7 +533,7 @@ To forward and receive combined messages, refer to the following code: ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```javascript connection.downloadAndParseCombineMessage({ diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 01574df4e..551a4242c 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -419,7 +419,7 @@ To forward and receive combined messages, refer to the following code: )); ``` -2. Download and parse combined messages: +1. Download and parse combined messages: ```csharp SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index d31f24b75..06300c500 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -64,9 +64,9 @@ This feature has the following limitations: * End users can only edit messages sent by themselves and not others. * Supported message types: text only. -* Supported use case: 1:1 & chat group. Do not support Chatroom. +* Supported use case: One-on-one chat group. Does not support Chatroom. * End users can recall and edit messages that were sent up to 7 days ago. -* We support editing the same message for up to 5 times. +* Agora supports editing the same message up to 5 times. ### RESTful API Call limit of server-side From 1e7c621ceece9b1cde87e68a22d868061a4aeb98 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Wed, 25 Oct 2023 16:54:25 +0300 Subject: [PATCH 08/37] Changes without reference --- .../project-implementation/android.mdx | 80 +------------ .../project-implementation/flutter.mdx | 57 +-------- .../project-implementation/ios.mdx | 51 +------- .../project-implementation/react-native.mdx | 71 +----------- .../project-implementation/unity.mdx | 80 +------------ .../project-implementation/web.mdx | 109 +++--------------- .../project-implementation/windows.mdx | 81 +------------ .../restful-api/_message-management.mdx | 31 ++--- 8 files changed, 48 insertions(+), 512 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 3d6380452..879b943d9 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -67,7 +67,9 @@ ChatClient.getInstance().chatManager().removeMessageListener(msgListener); ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. + +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```java try { @@ -336,80 +338,4 @@ ChatClient.getInstance().chatManager().sendMessage(message); message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attribute2", false) ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```java - ChatMessage message = ChatMessage.createCombinedSendMessage(title, summary, compatibleText, msgIds, toChatUsername); - // Set the chat type: - // One-to-one chat: ChatMessage.ChatType.Chat - // Group chat: ChatMessage.GroupChat - // Room chat: ChatMessage.ChatRoom - message.setChatType(ChatMessage.ChatType.Chat); - // Send the message - ChatClient.getInstance().chatManager().sendMessage(message); - ``` - -1. Download and parse combined messages: - - ```java - ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { - @Override - public void onSuccess(List value) { - - } - - @Override - public void onError(int error, String errorMsg) { - - } - }); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `asyncModifyMessage` with the message ID and the new message body: - - ```java - String newContent="new content"; - TextMessageBody newTextMessageBody = new TextMessageBody(newContent); - ChatClient.getInstance().chatManager().asyncModifyMessage(targetMessage.getMsgId(), newTextMessageBody, new ValueCallBack() { - @Override - public void onSuccess(ChatMessage value) { - - } - - @Override - public void onError(int error, String errorMsg) { - - } - }); - ``` - -1. Receive notification of messages modified by other users: - - ```java - // Create a MessageListener object - MessageListener messageListener = new MessageListener() { - //…… - - @Override - public void onMessageContentChanged(ChatMessage messageModified, String operatorId, long operationTime) { - // int operationCount = messageModified.getBody().operationCount(); - // operatorId and operationTime can also be obtained as follows: - // String id = messageModified.getBody().operatorId(); - // long time = messageModified.getBody().operationTime(); - } - }; - // Register the messageListener - ChatClient.getInstance().chatManager().addMessageListener(messageListener); - // Remove the messageListener - ChatClient.getInstance().chatManager().removeMessageListener(messageListener); - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 55fefe8ff..1e2cb66b1 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -255,7 +255,9 @@ String? thumbnailLocalPath = imgBody.thumbnailLocalPath; ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. + +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```dart try { @@ -274,57 +276,4 @@ ChatClient.getInstance.chatManager.addEventHandler( ); ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```dart - String title = "Historical messages for one-to-one chats between A and B"; - String summary = - "A: These are historical messages from A. \nB: These are historical messages from B."; - String compatibleText = - "Your current version does not support this type of message. Please upgrade to the latest version."; - final msg = ChatMessage.createCombineSendMessage( - targetId: targetId, - msgIds: msgIds, - title: title, - summary: summary, - compatibleText: compatibleText, - ); - await ChatClient.getInstance.chatManager.sendMessage(msg); - ``` - -1. Download and parse combined messages: - - ```dart - List list = - await ChatClient.getInstance.chatManager.fetchCombineMessageDetail( - message: combineMessage, - ); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `modifyMessage` with the message ID and the new message body: - - ```dart - ChatTextMessageBody body = ChatTextMessageBody(content: "new content"); - await ChatClient.getInstance.chatManager.modifyMessage( - messageId: msgId, - msgBody: body, - ); - ``` - -1. Receive notification of messages modified by other users: - - ```dart - ChatEventHandler( - onMessageContentChanged: (message, operatorId, operationTime) {}, - ) - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 6527d39e8..17d7029dc 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -68,7 +68,8 @@ When a message arrives, the recipient receives an `messagesDidReceive` callback. ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `recallMessageWithMessageId` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```objective-c [[AgoraChatClient sharedClient].chatManager recallMessageWithMessageId:@"messageId" completion:^(AgoraChatError *aError) { @@ -356,52 +357,4 @@ message.chatType = AgoraChatTypeChat; } ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```objective-c - AgoraChatCombineMessageBody *body = [[AgoraChatCombineMessageBody alloc] initWithTitle:@"Chat History" summary:@"summary" compatibleText:@"The version is low and unable to display the content." messageIdList:@[@"messageId1",@"messageId2"]]; - AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:@"conversationId" body:body ext:nil]; - [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:^(AgoraChatMessage *aMessage, AgoraChatError *aError) { - }]; - ``` - -1. Download and parse combined messages: - - ```objective-c - - (void)messagesDidReceive:(NSArray *)aMessages - { - for(AgoraChatMessage* msg in aMessages) { - if (msg.body.type == AgoraChatMessageBodyTypeCombine) { - [AgoraChatClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, AgoraChatError * _Nullable error) { - - }]; - } - } - } - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `modifyMessage` with the message ID and the new message body: - - ```objective-c - AgoraChatTextMessageBody* newBody = [[AgoraChatTextMessageBody alloc] initWithText:@"new content"]; - [AgoraChatClient.sharedClient.chatManager modifyMessage:msgId body:newBody completion:^(AgoraChatError * _Nullable error, AgoraChatMessage * _Nullable message) { - - }]; - ``` - -1. Receive notification of messages modified by other users: - - ```objective-c - - (void)onMessageContentChanged:(AgoraChatMessage *)message operatorId:(NSString *)operatorId operationTime:(NSUInteger)operationTime { - - } - ``` \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index 54e808f19..b7b4d8027 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -186,7 +186,9 @@ ChatClient.getInstance().chatManager.removeAllMessageListener(); ``` ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. + +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```typescript ChatClient.getInstance() @@ -204,71 +206,4 @@ You can also use `ChatMessageEventListener` to listen for the state of recalling onMessagesRecalled(messages: ChatMessage[]): void; ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```typescript - // Construct a combined message. - const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { - title, - summary, - compatibleText, - }); - EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); - ``` - -1. Download and parse combined messages: - - ```typescript - // message: The combined message object. - // Asynchronously return the list of original messages. - ChatClient.getInstance() - .chatManager.fetchCombineMessageDetail(message) - .then((messages: ChatMessage[]) => { - console.log("success: ", messages); - }) - .catch((error) => { - console.log("fail: ", error); - }); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `modifyMessageBody` with the message ID and the new message body: - - ```typescript - ChatClient.getInstance() - .chatManager.modifyMessageBody(msgId, body) - .then((message) => { - console.log("modify success:", message); - }) - .catch((error) => { - console.warn(error); - }); - ``` - -1. Receive notification of messages modified by other users: - - ```typescript - ChatClient.getInstance().chatManager.addMessageListener({ - onMessageContentChanged: ( - message: ChatMessage, - lastModifyOperatorId: string, - lastModifyTime: number - ): void => { - console.log( - `${QuickTestScreenChat.TAG}: onMessageContentChanged: `, - JSON.stringify(message), - lastModifyOperatorId, - lastModifyTime - ); - }, - } as ChatMessageEventListener); - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 20726cc16..b93bdca61 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -59,8 +59,9 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```csharp // Call `RecallMessage` to recall the message. SDKClient.Instance.ChatManager.RecallMessage("Message ID", new CallBack( @@ -398,81 +399,4 @@ if (found) { } ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```csharp - String title = "Historical messages for one-to-one chats between A and B"; - String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; - String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; - Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); - - SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - // Handling logic upon sending success - }, - onError: (code, desc) => { - // Handling logic if sendMessage fails - } - )); - ``` - -1. Download and parse combined messages: - - ```csharp - SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) => { - // Add the handling logic and show the message list - }, - onError: (code, desc) => { - // Handle an error - } - )); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `ModifyMessage` with the message ID and the new message body: - - ```csharp - TextBody tb = new TextBody("new content"); - SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( - onSuccess: (dmsg) => - { - - }, - onError: (code, desc) => - { - - } - )); - ``` - -1. Receive notification of messages modified by other users: - - ```csharp - // Inherit and implement `IChatManagerDelegate`. - public class ChatManagerDelegate : IChatManagerDelegate { - - public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) - { - // You can obtain operatorId and operationTime as follows: - // string id = msg.Body.OperatorId; - // long time = msg.Body.OperationTime; - } - } - - // Add a delegate. - ChatManagerDelegate adelegate = new ChatManagerDelegate(); - SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - - // Remove the delegate when it is no longer required - SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index aac5fb97f..dfb020901 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -119,7 +119,9 @@ WebIM.conn.addEventHandler("eventName",{ ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `recallMessage` method recalls a message saved on the server, whether it is a historical message, offline message or a roaming message. + +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```javascript /** @@ -128,15 +130,21 @@ By default, two minutes after a user sends a message, they can withdraw it. You * @param {Object} option.type - The message type: chat (one-to-one chat), group chat or chat room. */ let option = { - mid: 'msgId', - to: 'userID', - chatType: 'singleChat' + // The ID of the message to recall. + mid: "msgId", + // The message recipient. + to: "userID", + // The message type: singleChat, groupChat, and chatRoom respectively indicate one-to-one chat, group chat, and room chat. + chatType: "singleChat", }; -connection.recallMessage(option).then((res) => { - console.log('success', res) -}).catch((error) => { +connection + .recallMessage(option) + .then((res) => { + console.log("success", res); + }) + .catch((error) => { // Recalling the message fails, probably because the time limit for recalling the message is exceeded. - console.log('fail', error) + console.log("fail", error); ``` You can also use `onRecallMessage` to listen for the message recall state: ```javascript @@ -494,89 +502,4 @@ function sendPrivateText() { } ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```javascript - let option = { - chatType: "singleChat", - type: "combine", - to: "userId", - compatibleText: "Your SDK does not support combined messages. Please upgrade.", - title: "Chat history", - summary: "hi", - messageList: [ - // message body - { - type: "txt", - chatType: "singleChat", - // ... - }, - ], - onFileUploadComplete: (data) => { - option.url = data.url; - }, - }; - let msg = AC.message.create(option); - connection.send - .send(msg) - .then((res) => { - console.log("Succeeded in sending the message", res); - }) - .catch((err) => { - console.log("Failed to send the message", err); - }); - - ``` - - -1. Download and parse combined messages: - - ```javascript - connection.downloadAndParseCombineMessage({ - url: msg.url, - secret: msg.secret, - }) - .then((res) => { - console.log("The list of original messages obtained after parsing", res); - }); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `modifyMessage` with the message ID and the new message body: - - ```javascript - const textMessage = AC.message.create({ - type: 'txt', - msg: 'message content', - to: 'username', - chatType: 'singleChat', - }); - - connection.modifyMessage({ messageId: 'messageId', modifiedMessage: textMessage }) - .then((res) => { - console.log(res.message) - }) - .catch((e) => { - console.log(e) - }); - ``` - -1. Receive notification of messages modified by other users: - - ```javascript - // Adds the message modification event - connection.addEventHandler("modifiedMessage", { - onModifiedMessage: message => { - console.log('onModifiedMessage', message) - }, - }); - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 551a4242c..a40372a00 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -59,7 +59,9 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); ### Recall a message -By default, two minutes after a user sends a message, they can withdraw it. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. + +You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). ```csharp // Call `RecallMessage` to recall the message. @@ -397,81 +399,4 @@ if (found) { // Use variable b. } ``` -### Forward multiple messages - -To forward and receive combined messages, refer to the following code: - -1. Create a combined message using multiple message IDs: - - ```csharp - String title = "Historical messages for one-to-one chats between A and B"; - String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; - String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; - Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); - - SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - // Handling logic upon sending success - }, - onError: (code, desc) => { - // Handling logic if sendMessage fails - } - )); - ``` - -1. Download and parse combined messages: - - ```csharp - SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) => { - // Add the handling logic and show the message list - }, - onError: (code, desc) => { - // Handle an error - } - )); - ``` - -### Modify sent messages - -To modify a sent message, refer to the following code: - -1. Call `ModifyMessage` with the message ID and the new message body: - - ```csharp - TextBody tb = new TextBody("new content"); - SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( - onSuccess: (dmsg) => - { - - }, - onError: (code, desc) => - { - - } - )); - ``` - -1. Receive notification of messages modified by other users: - - ```csharp - // Inherit and implement `IChatManagerDelegate`. - public class ChatManagerDelegate : IChatManagerDelegate { - - public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) - { - // You can obtain operatorId and operationTime as follows: - // string id = msg.Body.OperatorId; - // long time = msg.Body.OperationTime; - } - } - - // Add a delegate. - ChatManagerDelegate adelegate = new ChatManagerDelegate(); - SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - - // Remove the delegate when it is no longer required. - SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); - ``` - \ No newline at end of file diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index 982af0faf..b989b7a51 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1442,7 +1442,8 @@ The fields of `bodies` for different message types vary: ## Recall a message -Once a message is sent, you can call this method to recall the message. The default time limit for recalling a message is two minutes. You can change this time frame and extend it no longer than 7 days in Agora Console. See [Enable and configure Chat](../get-started/enable). +Once a message is sent, you can call this API to recall it. This API recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. +The default time limit for recalling a message is two minutes. To adjust this limit, contact [support@agora.io](mailto:support@agora.io). For each App Key, the call frequency limit of this method is 100 per second. @@ -1467,11 +1468,11 @@ For the parameters and detailed descriptions, see [Common parameters](#param). | Parameter | Type | Required | Description | | :---------- | :------- | :------- | :----------------------------------------------------------- | -| `msg_id` | String | Yes | The ID of the recalled message. | -| `to` | String | No | The user, chat group, or chat room that receives the recalled message. You can specify a username, a chat group ID, or a chat room ID.
    **Note**: If the recalled message exceeds the message storage duration and no longer exists in the server, this message cannot be recalled on the server side. You can only recall the message on the receiver client instead. | -| `chat_type` | String | Yes | The type of the chat where the recalled message is located.
    • `chat`: A one-on-one chat.
    • `group_chat`: A chat group.
    • `chatroom`: A chat room.
    | +| `msg_id` | String | Yes | The ID of the message to recall. As only one message can be recalled each time, you can pass in only one message ID. | +| `to` | String | No | The user, chat group, or chat room that receives the message to recall. You can specify a user ID, a chat group ID, or a chat room ID.
    **Note**: If the message to recall no longer exists on the server, only the message on the recipient client is recalled. | +| `chat_type` | String | Yes | The type of the chat where the message to recall is sent.
    • `chat`: An one-on-one chat.
    • `groupchat`: A chat group.
    • `chatroom`: A chat room.
    | | `from` | String | No | The user who recalls the message. By default, the recaller is the app admin. You can also specify another user as the recaller. | -| `force` | bool | Yes | Whether to force a recall if the recalled message exceeds the message storage duration and no longer exists in the server.
    • `true`: Force the recall on the client that receives the message.
    • `false`: The recall fails.
    The maximum message storage duration varies based on different pricing plans. For details, see [Message storage duration](../reference/limitations#message-storage-duration). | +| `force` | bool | No | Whether to allow to recall messages beyond the storage time on the server. For details on the message storage duration on the server, see [Message storage duration](https://docs.agora.io/en/agora-chat/reference/limitations#message-storage-duration).
    • `true`: Yes. In this case, you can recall messages within the recall period or those beyond the storage time on the server. For the latter, this API recalls the messages locally saved by the recipient. If the message sending time is between your recall duration and the storage duration on the server, the recall fails. For example, if the recall duration is 2 minutes and the storage time on the server is 7 days, you can recall a message sent within 2 minutes or one that was sent more than 7 days ago; if the message is sent 3 minutes ago, the recall will fail.
    • `false`: No. You cannot recall messages beyond the storage time on the server. If you use the default recall time of 2 minutes or a custom duration, the server can only recall the messages sent within the specified time, and those beyond this time cannot be recalled. For example, if you set the recall time to 3 minutes and the message is sent 4 minutes ago, the recall will fail.
    | ### HTTP response @@ -1479,13 +1480,13 @@ For the parameters and detailed descriptions, see [Common parameters](#param). If the returned HTTP status code is `200`, the request succeeds, and the response body contains the following fields: -| Parameter | Description | -| :--------- | :----------------------------------------------------------- | -| `msg_id` | The ID of the recalled message. | -| `recalled` | Returns `yes` if the request is successful. | -| `from` | The user who recalls the message. By default, the recaller is the app admin. | -| `to` | The user, chat group, or chat room that receives the recalled message. | -| `chattype` | The type of the chat where the recalled message is located.
    • `chat`: A one-on-one chat.
    • `group_chat`: A chat group.
    • `chatroom`: A chat room.
    | +| Parameter | Type | Description | +| :--------- | :--------- | :----------------------------------------------------------- | +| `msg_id` | String | The ID of the recalled message. | +| `recalled` | String | Returns `yes` if the request is successful. | +| `from` | String | The user who recalls the message. By default, the recaller is the app admin. | +| `to` | String | The user, chat group, or chat room that receives the recalled message. | +| `chattype` | String | The type of the chat where the recalled message is located.
    • `chat`: An one-on-one chat.
    • `group_chat`: A chat group.
    • `chatroom`: A chat room.
    | For other fields and detailed descriptions, see [Common parameters](#param). @@ -1546,9 +1547,9 @@ curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json ``` Possible causes for failing to recall the message include the following: - - `"can't find message to"`: Fails to find the recipient of the message. - - `"exceed call time limit"`: Exceeds the time limit for recalling a message. - - `"not_found msg"`: The message is recalled. + - `"can't find message to"`: The recipient of the message to recall is not found. + - `"exceed call time limit"`: The time limit for recalling a message is exceeded. + - `"not_found msg"`: The message is already recalled or no longer exists because its storage period expires. - `"internal error"`: An internal error occurs with the back-end service. From 9481bfd39b15216ab4eabaaf26dda3679be43e65 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 26 Oct 2023 17:09:59 +0300 Subject: [PATCH 09/37] RESTful API update --- .../reference/error-codes/android.mdx | 176 ++++++++++-------- shared/chat-sdk/reference/error-codes/ios.mdx | 170 +++++++++-------- shared/chat-sdk/reference/error-codes/web.mdx | 103 +++++----- .../reference/error-codes/windows.mdx | 152 ++++++++------- .../restful-api/_message-management.mdx | 2 +- 5 files changed, 336 insertions(+), 267 deletions(-) diff --git a/shared/chat-sdk/reference/error-codes/android.mdx b/shared/chat-sdk/reference/error-codes/android.mdx index 7cbbe634d..64a77c1d5 100644 --- a/shared/chat-sdk/reference/error-codes/android.mdx +++ b/shared/chat-sdk/reference/error-codes/android.mdx @@ -7,84 +7,102 @@ The error codes and error messages might be returned in the following ways: | Error code | Error message | Possible reason | | :--------- | :--------------- | :------------------- | -| 0 | `EM_NO_ERROR` | None | -| 1 | `GENERAL_ERROR` | The SDK has not been successfully initialized, or the specified reason for the error is not identified when you request the server. You can try reinitializing the SDK. | -| 2 | `NETWORK_ERROR` | Disconnections between the SDK and the server happen due to the network problems. | -| 4 | `EXCEED_SERVICE_LIMIT` |The service limit is exceeded, for example, the total number of the registered users or their friends exceeds the plan limit. | -| 100 | `INVALID_APP_KEY` | The App Key is invalid. Log in again using a valid App Key. | -| 101 | `INVALID_USER_NAME` | The user ID is empty, or the format of the parameter is incorrect. Use a [valid user ID](/agora-chat/restful-api/user-system-registration). | -| 102 | `INVALID_PASSWORD` | The password entered to log in is empty or incorrect. Log in again using the correct password. | -| 104 | `INVALID_TOKEN` | The token entered to log in is empty or incorrect. Log in again using the correct token. | -| 200 | `USER_ALREADY_LOGIN` | The user has already logged in. Do not log in repeatedly. | -| 201 | `USER_NOT_LOGIN` | The user has not logged in when the method is called. Please check the your code logic. | -| 202 | `USER_AUTHENTICATION_FAILED` | The user authentication fails. Check whether the token has expired. | -| 203 | `USER_ALREADY_EXIST` | A user with the same user ID is already logged in. Do not register repeatedly. | -| 204 | `USER_NOT_FOUND` | The user is not registered when the method is called. Register before doing any other operation. | -| 205 | `USER_ILLEGAL_ARGUMENT` | An invalid parameter is used when you call the method. For example, invalid characters are found in the specified user ID. Reset the parameter. | -| 206 | `USER_LOGIN_ANOTHER_DEVICE` | If the user does not enable multi-device login, the user is forced to log out when logging in at another device, and the SDK returns this error code. | -| 207 | `USER_REMOVED` | When the logged in user ID is deleted by the server, the SDK returns this error code. | -| 208 | `USER_REG_FAILED` | When you call the server registration method, the parameter passed is empty or invalid. See [User registration RESTful API](/agora-chat/restful-api/user-system-registration). | -| 209 | `PUSH_UPDATECONFIGS_FAILED` | The update push configuration fails. Update the nickname and the Do Not Disturb mode. Try calling the method again. | -| 210 | `USER_PERMISSION_DENIED` | The user has no permission to operate. Check whether the user is banned. If the user is banned, unban the user and log in again. | -| 213 | `USER_BIND_ANOTHER_DEVICE` | If the user sets the device login priority, that is, to log in at the device with higher priority, when the logged in user tries logging in at another device, the login fails, and the SDK returns this error code. | -| 214 | `USER_LOGIN_TOO_MANY_DEVICES` | If a user ID has logged in at four devices, when the user tries logging in at a fifth device, the SDK returns this error code. If you want a user to log in at more than four devices, contact [support@agora.io](mailto:support@agora.io). | -| 215 | `USER_MUTED` | If the user is muted in the group or the chatroom, when the user sends a message, the SDK returns this error code. | -| 216 | `USER_KICKED_BY_CHANGE_PASSWORD` | If the logged in user changes the present password, the SDK kicks the user out and returns this error code. | -| 217 | `USER_KICKED_BY_OTHER_DEVICE` | When the multi-device login function is enabled, if the user forces the user ID logged in at the current device to log out by calling APIs or managing the backend at another device, the SDK returns this error code. | -| 221 | `USER_NOT_FRIEND` | When a peer user sets not to receive messages from a user that is not a contact, if you send a message to this peer user, the SDK reports this error code. You can enable this service on Agora Console. | -| 300 | `SERVER_NOT_REACHABLE` | The SDK disconnects from the Chat system due to network problems. Try again later. | -| 301 | `SERVER_TIMEOUT` | Some API calls require the SDK to return the execution result. This error occurs if the SDK takes too long (more than 30 seconds) to return the result. | -| 302 | `SERVER_BUSY` | The server is currently busy. Try again later. | -| 303 | `SERVER_UNKNOWN_ERROR` | This common error occurs when the requesting service fails. Check the log for troubleshooting. | -| 304 | `SERVER_GET_DNSLIST_FAILED` | The SDK fails in getting the configuration of the server that the app currently runs on. Try calling the method again. | -| 305 | `SERVER_SERVICE_RESTRICTED` | If the app is banned, the SDK returns this error code when the methods are called. | -| 400 | `FILE_NOT_FOUND` | When the user is unable to get the log file or download the attachment, the SDK returns this error code. | -| 401 | `FILE_INVALID` | When the uploaded message attachment or the shared file in the group is invalid, the SDK returns this error code. | -| 402 | `FILE_UPLOAD_FAILED` | When the message attachment cannot be uploaded, the SDK returns this error code. Try uploading again. | -| 403 | `FILE_UPLOAD_FAILED` | When the message attachment cannot be downloaded, the SDK returns this error code. Try downloading again. | -| 404 | `FILE_DELETE_FAILED` | When getting the log file, the SDK deletes the old log file. If the old log files cannot be deleted, the SDK returns this error code. | -| 405 | `FILE_TOO_LARGE` | When the size of the message attachment or the group shared file exceeds the limit, the SDK returns this error code. Adjust the file size, and try uploading again. | -| 500 | `MESSAGE_INVALID` | The content of the message to be sent is empty, the message ID is empty, or the user ID of the sender is not the user ID that is currently logged in. Check the problems, and try sending the message again. | -| 502 | `MESSAGE_SEND_TRAFFIC_LIMIT` | The message-sending frequency is too high or the message size is too large. Agora recommends reducing the sending frequency or the message size. | -| 504 | `MESSAGE_RECALL_TIME_LIMIT` | When a timeout occurs during message recall, the SDK returns this error code. | -| 505 | `SERVICE_NOT_ENABLED` | When you try using a service that is not enabled, the SDK returns this error code. | -| 506 | `MESSAGE_EXPIRED` | If you send a group receipt after the time limit (the default is three days), the SDK returns this error code. | -| 507 | `MESSAGE_ILLEGAL_WHITELIST` | If all members are banned in the group or chat room and the user ID is not included in the allow list, when this user tries sending a message, the SDK returns this error code. | -| 600 | `GROUP_INVALID_ID` | When you call the methods related to the group and the group ID provided is invalid, the SDK returns this error code. | -| 601 | `GROUP_ALREADY_JOINED` | When you call the group joining method, if the user has already joined the group, the SDK returns this error code. | -| 602 | `GROUP_NOT_JOINED` | When you try sending messages or controlling a group that you have not joined, the SDK returns this error code. | -| 603 | `GROUP_PERMISSION_DENIED` | The user does not have permission to control the group, for example the group members do not have permission to set the group administrator. Check whether the user has administrator permissions. | -| 604 | `GROUP_MEMBERS_FULL` | The number of the group members has reached the limit. | -| 605 | `GROUP_NOT_EXIST` | When you try controlling a group that does not exist, the SDK returns this error code. | -| 700 | `CHATROOM_INVALID_ID` | When you call the methods related to the chatroom and the chatroom ID provided is empty, the SDK returns this error code. | -| 701 | `CHATROOM_ALREADY_JOINED` | When you call the chatroom-joining method, if the user has already joined the chatroom, the SDK returns this error code. | -| 702 | `CHATROOM_NOT_JOINED` | When you try sending messages or controlling a chatroom that you have not joined, the SDK returns this error code. | -| 703 | `CHATROOM_PERMISSION_DENIED` | The user does not have permission to control the chatroom, for example, the chatroom members do not have permission to set the chatroom administrator. Check whether the user has administrator permissions. | -| 704 | `CHATROOM_MEMBERS_FULL` | The number of the chatroom members has reached the limit. | -| 705 | `CHATROOM_NOT_EXIST` | When you try controlling a chatroom that does not exist, the SDK returns this error code. | -| 900 | `USERINFO_USERCOUNT_EXCEED` | The number of users from whom you request to retrieve the attributes exceeds the limit of 100. | -| 901 | `USERINFO_DATALENGTH_EXCEED` | The size of user attributes exceeds the limit, either individually or collectively. The size of attributes from each user cannot exceed 2 KB. The size of attributes from all users in an app cannot exceed 10 GB. | -| 903 | `TRANSLATE_INVALID_PARAMS` | The parameters you pass in when calling APIs of the translation service are invalid. | -| 904 | `TRANSLATE_FAIL` | The request to translate fails. | -| 905 | `TRANSLATE_NOT_INIT` | The translation service has not been initialized. | -| 1000 | `CONTACT_ADD_FAILED` | The request to add a contact fails. | -| 1001 | `CONTACT_REACH_LIMIT` | You cannot add a contact because the number of your contacts has reached the limit. | -| 1002 | `CONTACT_REACH_LIMIT_PEER` | You cannot add a contact because the number of peer contacts has reached the limit. | -| 1100 | `PRESENCE_PARAM_LENGTH_EXCEED` | The length of the parameters you pass in when calling APIs of the presence service exceed the limit. | -| 1110 | `TRANSLATE_PARAM_INVALID` | The parameters you pass in when calling APIs of the translation service are invalid. | -| 1111 | `TRANSLATE_SERVICE_NOT_ENABLE` | The translation service has not been activated. | -| 1112 | `TRANSLATE_USAGE_LIMIT` | The usage of the translation service exceeds the limit. | -| 1113 | `TRANSLATE_MESSAGE_FAIL` | The request to retrieve the translation service fails. | -| 1200 | `MODERATION_FAILED` | The third-party content moderation service of Chat rates the message as "Reject". | -| 1299 | `THIRD_SERVER_FAILED` | Another service rather than the third-party content moderation service of Chat rates the message as "Reject". | -| 1300 | `REACTION_REACH_LIMIT` | The number of reactions exceeds the limit. | -| 1301 | `REACTION_HAS_BEEN_OPERATED` | The reaction to add already exists in your reaction list. | -| 1302 | `REACTION_OPERATION_IS_ILLEGAL` | You do not have the permission to perform that operation to a reaction. For example, you cannot delete a reaction if the reaction does not exist in your reaction list. | -| 1400 | `THREAD_NOT_EXIST` | The thread does not exist. | -| 1401 | `THREAD_ALREADY_EXIST` | The thread you are attempting to create already exists in a chat group. | -| 1402 | `THREAD_CREATE_MESSAGE_ILLEGAL` | The request to send a message in a thread fails because the parent message of the thread is recalled. | -| 1500 | `PUSH_NOT_SUPPORT` | The third-party push service is not supported on the current device. | -| 1501 | `PUSH_BIND_FAILED` | The token of the third-party push service fails to upload to the server. | -| 1502 | `PUSH_UNBIND_FAILED` | The token of the third-party push service fails to unbind. | +| 0 | `EM_NO_ERROR` | The operation succeeds. | +| 1 | `GENERAL_ERROR` | Default error related to the SDK or requests to the server. For example, the SDK is not properly initialized, or a request fails with no specific reason. | +| 2 | `NETWORK_ERROR` | The SDK is disconnected from the server due to network interruption. | +| 3 | `DATABASE_ERROR` | The database operation fails. | +| 4 | `EXCEED_SERVICE_LIMIT` | The usage exceeds the service limit. For example, the total number of registered users or contacts exceeds the limit of the current [pricing plan](https://docs.agora.io/en/agora-chat/reference/pricing-plan-details?platform=ios). | +| 8 | `APP_ACTIVE_NUMBER_REACH_LIMITATION` | The app has reached its maximum number of daily active users (DAU) or monthly active users (MAU). | +| 100 | `INVALID_APP_KEY` | The App Key is invalid. For how to get the App Key, see [Get the information of the Agora Chat project](https://docs.agora.io/en/agora-chat/get-started/enable?platform=android#get-chat-project-information). | +| 101 | `INVALID_USER_NAME` | The user ID is invalid. For example, when a user requests to add a contact, the user ID is set to an empty string. | +| 102 | `INVALID_PASSWORD` | The login password is empty or invalid. | +| 104 | `INVALID_TOKEN` | The user token is empty or invalid. | +| 105 | `USER_NAME_TOO_LONG` | The length of the user ID exceeds the limit of 64 bytes. | +| 108 | `TOKEN_EXPIRED` | The token has expired. | +| 109 | `TOKEN_WILL_EXPIRE` | The token has passed half of its validity period. | +| 110 | `INVALID_PARAM` | Invalid parameter. | +| 200 | `USER_ALREADY_LOGIN` | The user has already logged in. | +| 201 | `USER_NOT_LOGIN` | The user hasn't logged in. For example, the login session is either invalid or has expired when a user requests to send a message or perform operations to a chat group. | +| 202 | `USER_AUTHENTICATION_FAILED` | The user authentication fails because the token is invalid or has expired. | +| 203 | `USER_ALREADY_EXIST` | The user already exists: The user ID specified during user account registration already exists. | +| 204 | `USER_NOT_FOUND` | The user does not exist. For example, the user ID specified for login or retrieval of the conversation list of a user does not exist. | +| 205 | `USER_ILLEGAL_ARGUMENT` | Incorrect user parameter. For example, the user ID specified during user account registration or user attribute updating is invalid or empty. | +| 206 | `USER_LOGIN_ANOTHER_DEVICE` | The user has logged in on another device. If the multi-device service is not enabled, the user is forced to log out of the current device upon successful login on another device with the same account. | +| 207 | `USER_REMOVED` | The user account is deleted on the [Agora Console](https://console.agora.io/). | +| 209 | `PUSH_UPDATECONFIGS_FAILED` | Fails to update the push configurations. For example, a failure of changing the nickname displayed for message push or updating do-not-disturb settings. | +| 210 | `USER_PERMISSION_DENIED` | The user has no permission to perform this operation. For example, a user that is banned attempts to send a message. | +| 213 | `USER_BIND_ANOTHER_DEVICE` | The user has logged in to another device. This error occurs when a user has logged in on one device and try to log in on another one with the same account, if the app is configured to persist the login state on the current device while preventing the login on another device in a single-device login scenario. This error code is deprecated. | +| 214 | `USER_LOGIN_TOO_MANY_DEVICES` | The user has reached the maximum number of devices on which he or she can log in with the same user account. This error occurs on a device with auto login enabled in a multi-device login scenario if the app turns on the switch of login on another device never kicking the user off on a current login device when the maximum number of login devices is exceeded. For example, a user can log in on at most four devices. At first, the user stays logged in on four devices, A (with auto login enabled), B, C, D. Then, the user gets logged out on device A due to network disruption and logs in on device E manually. After the network is available, auto login is performed on device A and fails due to the limit of login devices, triggering this error. | +| 215 | `USER_MUTED` | The user is muted and not allowed to send messages in a chat group or chat room. | +| 216 | `USER_KICKED_BY_CHANGE_PASSWORD` | The user has changed the login password. Once the login password is changed, the current login session ends and the user must log in again with the new password. | +| 217 | `USER_KICKED_BY_OTHER_DEVICE` | The user gets kicked off from a device in a multi-device login scenario on the [Agora Console](https://console.agora.io/) or by calling an API on another device. | +| 218 | `USER_ALREADY_LOGIN_ANOTHER` | Another user has logged in. This error occurs if a user attempts to log in on the same device with another account before logging out on the device with the current account. | +| 219 | `USER_MUTED_BY_ADMIN` | The user is muted globally and cannot send a message. | +| 220 | `USER_DEVICE_CHANGED` | The device on which a user attempts to log in is not the last one in a single-device login scenario. By default, if a user logs in on a another device, he or she will get kicked off from the current device in a single-device login scenario. This error occurs if the app turns on the switch of keeping the logged-in state on the current device if a user attempts to log in on another device. | +| 221 | `USER_NOT_ON_ROSTER` | The user cannot send a message to another user that is not on the contact list. This error occurs if the switch of allowing message sending only between contacts is turned on. | +| 300 | `SERVER_NOT_REACHABLE` | The server is not reachable. For example, the SDK is disconnected from the server due to unstable network conditions or other reasons when a user sends or recalls a message. | +| 301 | `SERVER_TIMEOUT` | The request timeout. This error occurs when the server does not respond to an API request within the specified period, generally 30 or 60 seconds.| +| 302 | `SERVER_BUSY` | The server is currently busy. Try again later. | +| 303 | `SERVER_UNKNOWN_ERROR` | A common error for requests to the server. As this error occurs in multiple cases, the user needs to further identify and troubleshoot issues according to logs. | +| 304 | `SERVER_GET_DNSLIST_FAILED` | The SDK fails in getting the configuration of the server that the app currently runs on. | +| 305 | `SERVER_SERVICE_RESTRICTED` | The app is banned. This error occurs if a user tries to call a method when the app is banned. | +| 400 | `FILE_NOT_FOUND` | The file is not found. For example, a log file is not found or downloading an attachment fails. | +| 401 | `FILE_INVALID` | The file is invalid. For example, uploading a message attachment or a shared file in the group fails. | +| 402 | `FILE_UPLOAD_FAILED` | Fails to upload a file. For example, uploading a message attachment fails. | +| 403 | `FILE_DOWNLOAD_FAILED` | Fails to download a file. For example, downloading a message attachment fails. | +| 404 | `FILE_DELETE_FAILED` | Fails to delete the existing log file. When a user retrieves a new log file, the existing log file, if any, will be deleted before a new one is generated. | +| 405 | `FILE_TOO_LARGE` | The file is too large. For example, the message attachment or shared group file that a user attempts to upload exceeds the file size limit for upload. | +| 406 | `FILE_CONTENT_IMPROPER` | The file content is inappropriate. For example, a message attachment or shared group file fails to be uploaded because the file contains inappropriate contents. | +| 500 | `MESSAGE_INVALID` | The message is invalid. For example, during message sending, the message object or message ID is empty, or the user ID of the message sender is inconsistent with the user ID of the current login session. | +| 501 | `MESSAGE_INCLUDE_ILLEGAL_CONTENT` | The message contains inappropriate content. This error occurs when a message is found by the filtering system to contain inappropriate content. | +| 502 | `MESSAGE_SEND_TRAFFIC_LIMIT` | Messages are too large or sent too frequently. It is recommended that the user reduce the message sending frequency or the message size. | +| 504 | `MESSAGE_RECALL_TIME_LIMIT` | The message recall timeout. This error occurs when a message fails to be recalled because the timeout period expires. | +| 505 | `SERVICE_NOT_ENABLED` | The feature that the user is attempting to use is not enabled. This feature needs to be enabled on the [Agora Console](https://console.agora.io/) or by contacting [support@agora.io](mailto:support@agora.io) before it is ready to use. | +| 506 | `MESSAGE_EXPIRED` | The period for sending the read receipt for a group message has expired. The default validity period is 3 days. | +| 507 | `MESSAGE_ILLEGAL_WHITELIST` | The user is not on the allow list of a group or chat room. This error occurs when a user that is not on the allow list attempts to send a message in a chat group or chat room if all members of the group or chat room are muted. | +| 508 | `MESSAGE_EXTERNAL_LOGIC_BLOCKED` | During the pre-sending callback, the message that the user is attempting to send is blocked by a message filtering rule defined in the app server. | +| 510 | `MESSAGE_SIZE_LIMIT` | The body of the message to send exceeds the upper limit. | +| 511 | `MESSAGE_EDIT_FAILED` | Fails to modify a message. | +| 600 | `GROUP_INVALID_ID` | Invalid group ID. For a group-related API, the chat group ID is an empty string or invalid. | +| 601 | `GROUP_ALREADY_JOINED` | The user is already in this chat group. For example, the error occurs when a user attempts to join a chat group that he or she is already in.| +| 602 | `GROUP_NOT_JOINED` | The user hasn't joined this chat group. This error occurs when a user attempts to send a message or perform operations in a chat group that he or she is not in. | +| 603 | `GROUP_PERMISSION_DENIED` | The user does not have the permission to perform the operation to a chat group. For example, a chat group member does not have permission to add or remove a chat group admin. | +| 604 | `GROUP_MEMBERS_FULL` | The number of members in the chat group has reached the upper limit specified during group creation.| +| 605 | `GROUP_SHARED_FILE_INVALIDID` | The ID of the shared file in the chat group is invalid. | +| 606 | `GROUP_NOT_EXIST` | The chat group to which the user is requesting to perform operations does not exist. | +| 607 | `GROUP_DISABLED` | The chat group is disabled. | +| 608 | `GROUP_NAME_VIOLATION` | The chat group name is invalid. | +| 609 | `GROUP_MEMBER_ATTRIBUTES_REACH_LIMIT` | The number of custom attributes has reached the upper limit for a chat group member. | +| 610 | `GROUP_MEMBER_ATTRIBUTES_UPDATE_FAILED` | Fails to set custom attributes for a chat group member. | +| 611 | `GROUP_MEMBER_ATTRIBUTES_KEY_REACH_LIMIT` | The key of a custom attribute for a chat group member exceeds the limit of 16 bytes. | +| 612 | `GROUP_MEMBER_ATTRIBUTES_VALUE_REACH_LIMIT` | The value of a custom attribute for a chat group member exceeds the limit of 512 bytes. | +| 700 | `CHATROOM_INVALID_ID` | Invalid chat room ID. This error occurs when the chat room ID is an empty string for the chat room-related method that is used. | +| 701 | `CHATROOM_ALREADY_JOINED` | The user is already in the chat room. This error occurs when a user attempts to join a chat room that he or she is already in. | +| 702 | `CHATROOM_NOT_JOINED` | The user hasn't joined this chat room. This error occurs when a user attempts to send a message or perform operations in a chat room that he or she is not in. | +| 703 | `CHATROOM_PERMISSION_DENIED` | The user does not have the permission to perform the operation to a chat room. For example, a chat room member does not have permission to add or remove a chat room admin. | +| 704 | `CHATROOM_MEMBERS_FULL` | The number of members in the chat room has reached the upper limit specified during chat room creation. | +| 705 | `CHATROOM_NOT_EXIST` | The chat room to which the user is requesting to perform operations does not exist. | +| 900 | `USERINFO_USERCOUNT_EXCEED` | The number of users whose user attributes are to be retrieved exceeds 100.| +| 901 | `USERINFO_DATALENGTH_EXCEED` | The user attributes are too long. The total length of all user attributes cannot exceed 2 KB for a user or 10 GB for an app.| +| 1000 | `CONTACT_ADD_FAILED` | Fails to add a contact. | +| 1001 | `CONTACT_REACH_LIMIT` | The inviter has reached the maximum number of contacts that can be added. | +| 1002 | `CONTACT_REACH_LIMIT_PEER` | The invitee has reached the maximum number of contacts that can be added. | +| 1100 | `PRESENCE_PARAM_LENGTH_EXCEED` | The length of a parameter in the presence-related API call exceeds the upper limit. | +| 1101 | `PRESENCE_CANNOT_SUBSCRIBE_YOURSELF` | The user cannot subscribe to her or his own presence status. | +| 1110 | `TRANSLATE_PARAM_INVALID` | Translation parameter error. | +| 1111 | `TRANSLATE_SERVICE_NOT_ENABLE` | The translation service has not been enabled. The translation service needs to be enabled on the [Agora Console](https://console.agora.io/) before it is ready to use. | +| 1112 | `TRANSLATE_USAGE_LIMIT` | The translation usage has reached the upper limit. | +| 1113 | `TRANSLATE_MESSAGE_FAIL` | Fails to translate the message. | +| 1200 | `MODERATION_FAILED` | The message moderation result provided by the third-party content moderation service is `Rejected`. | +| 1299 | `THIRD_SERVER_FAILED` | The content moderation result of another moderation service than the third-party service is `Rejected`. | +| 1300 | `REACTION_REACH_LIMIT` | The number of Reactions for the message has reached the maximum allowed. | +| 1301 | `REACTION_HAS_BEEN_OPERATED` | The user has added this Reaction and cannot add it repeatedly. | +| 1302 | `REACTION_OPERATION_IS_ILLEGAL` | The user does not have permission to operate on this Reaction. For example, a user that does not add this Reaction attempts to delete it or a user that is neither the message sender nor recipient tries to add a Reaction in a one-to-one chat. | +| 1400 | `THREAD_NOT_EXIST` | The thread does not exist. | +| 1401 | `THREAD_ALREADY_EXIST` | The thread to be created already exists. | +| 1402 | `THREAD_CREATE_MESSAGE_ILLEGAL` | The parent message for thread creation is invalid. For example, the message is recalled or unavailable. | +| 1500 | `PUSH_NOT_SUPPORT` | The third-party push service is not supported. This error occurs if the configured third-party push service is not supported by the current device. | +| 1501 | `PUSH_BIND_FAILED` | Fails to bind the device with the push token provided by a third-party push service. This error occurs when the token of a third-party push service fails to be uploaded to the server. | +| 1502 | `PUSH_UNBIND_FAILED` | Fails to unbind the device from the push token provided by a third-party push service.| \ No newline at end of file diff --git a/shared/chat-sdk/reference/error-codes/ios.mdx b/shared/chat-sdk/reference/error-codes/ios.mdx index ff68ba1a9..ab894fc98 100644 --- a/shared/chat-sdk/reference/error-codes/ios.mdx +++ b/shared/chat-sdk/reference/error-codes/ios.mdx @@ -4,85 +4,101 @@ During the run time of the Chat SDK, if the method call succeeds, the SDK return | Error code | Error message | Possible reason | | :----- | :----------------------------------- | :----------------------------------------------------------- | -| 1 | `AgoraChatErrorGeneral` | The SDK has not been successfully initialized, or the specified reason for the error is not identified when you request the server. You can try reinitializing the SDK. | -| 2 | `AgoraChatErrorNetworkUnavailable` | Disconnections between the SDK and the server happen due to the network problems. | -| 3 | `AgoraChatErrorDatabaseOperationFailed` | Fails to open local database. Please contact Agora technical support. | -| 4 | `AgoraChatErrorExceedServiceLimit` | The service limit is exceeded, for example: the total number of registered users or their friends exceeds the plan limit described in [Package plan](../reference/pricing-plan-details). | -| 100 | `AgoraChatErrorInvalidAppkey` | The App Key is invalid. Log in again using a valid App Key. For how to get the App Key, see [Get the information of the Chat project](/agora-chat/get-started/enable#get-the-information-of-the-agora-chat-project). | -| 101 | `AgoraChatErrorInvalidUsername` | The user ID is empty, or the format of the parameter is incorrect. Use a valid user ID. | -| 102 | `AgoraChatErrorInvalidPassword` | The password entered to log in is empty or incorrect. Log in again using the correct password. | +| 0 | `AgoraChatErrorNoError` | The operation succeeds. | +| 1 | `AgoraChatErrorGeneral` | Default error related to the SDK or requests to the server. For example, the SDK is not properly initialized, or a request fails with no specific reason. | +| 2 | `AgoraChatErrorNetworkUnavailable` | The SDK is disconnected from the server due to network interruption. | +| 3 | `AgoraChatErrorDatabaseOperationFailed` | The database operation fails. | +| 4 | `AgoraChatErrorExceedServiceLimit` | The usage exceeds the service limit. For example, the total number of registered users or contacts exceeds the limit of the current [pricing plan](https://docs.agora.io/en/agora-chat/reference/pricing-plan-details?platform=ios). | +| 8 | `AgoraChatAppActiveNumbersReachLimitation` | The app has reached its maximum number of daily active users (DAU) or monthly active users (MAU). | +| 100 | `AgoraChatErrorInvalidAppkey` | The App Key is invalid. For how to get the App Key, see [Get the information of the Agora Chat project](https://docs.agora.io/en/agora-chat/get-started/enable?platform=android#get-chat-project-information). | +| 101 | `AgoraChatErrorInvalidUsername` | The user ID is invalid. For example, when you request to add a contact, the user ID is set to an empty string. | +| 102 | `AgoraChatErrorInvalidPassword` | The login password is empty or invalid. | | 104 | `AgoraChatErrorUsernameTooLong` | The user ID is too long. Log in again with a valid user ID. | -| 200 | `AgoraChatErrorUserAlreadyLoginSame` | This user is already logged in. Do not log in repeatedly. | -| 201 | `AgoraChatErrorUserNotLogin` | The user is not logged in when the method is called. Please check your code logic. | -| 202 | `AgoraChatErrorUserAuthenticationFailed` | The user authentication fails. Check whether the token has expired. | -| 203 | `AgoraChatErrorUserAlreadyExist` | A user with the same user ID is already logged in. Do not register repeatedly. | -| 204 | `AgoraChatErrorUserNotFound` | The user is not registered when the method is called. Register before doing any other operation. | -| 205 | `AgoraChatErrorUserIllegalArgument` | An invalid parameter is used when you call the method. For example, invalid characters are found in the specified user ID. Reset the parameters. | -| 206 | `AgoraChatErrorUserLoginOnAnotherDevice` | If the user does not enable multi-device login, the user is forced to log out when logging in at another device, and the SDK returns this error code. | -| 207 | `AgoraChatErrorUserRemoved` | When the logged in user ID is deleted by the server, the SDK returns this error code. | -| 208 | `AgoraChatErrorUserRegisterFailed` | When you call the server registration method, the parameter passed is empty or invalid. For details, see [User registration RESTful API](/agora-chat/restful-api/user-system-registration). | -| 209 | `AgoraChatErrorUpdateApnsConfigsFailed` | Fails to update the push message configurations, such as the push display nickname, do-not-disturb mode, etc. Try calling the method again. | -| 210 | `AgoraChatErrorUserPermissionDenied` | The user has no permission to operate. Check whether the user is banned. If the user is banned, unban the user and log in again. | -| 213 | `AgoraChatErrorUserBindAnotherDevice` | If the user sets the device login priority, that is, to log in at the device with higher priority, when the logged in user tries logging in to another device, the login fails, and the SDK returns the error code. | -| 214 | `AgoraChatErrorUserLoginTooManyDevices` | If a user ID is logged in at four devices, when the user tries logging in at a fifth device, the SDK returns this error code. If you want a user to log in at more than four devices, contact support@agora.io. | -| 215 | `AgoraChatErrorUserMuted` | If the user is muted in the group or the chatroom, when the user sends a message, the SDK returns this error code. | -| 216 | `AgoraChatErrorUserKickedByChangePassword` | If the logged in user changes the present password, the SDK kicks the user out and returns this error code. Try logging in again with the new password. | -| 217 | `AgoraChatErrorUserKickedByOtherDevice` | When the multi-device login function is enabled, if the user forces the user ID logged in at the current device to log out by calling APIs or managing the backend at another device, the SDK returns this error code. | -| 221 | `AgoraChatErrorUserNotOnRoster` | When a peer user sets not to receive messages from a user that is not a contact, if you send a message to this peer user, the SDK reports this error code. You can enable this feature on Agora Console. | -| 300 | `AgoraChatErrorServerNotReachable` | The SDK disconnects from the Chat system due to network problems. Try again later. | -| 301 | `AgoraChatErrorServerTimeout` |Some API calls require the SDK to return the execution result. This error occurs if the SDK takes too long (more than 30 seconds) to return the result. | -| 302 | `AgoraChatErrorServerBusy` |The server is currently busy. Try again later. | -| 303 | `AgoraChatErrorServerUnknownError` | This common error occurs when the requesting service fails. Check the log for troubleshooting. | -| 304 | `AgoraChatErrorServerGetDNSConfigFailed` | The SDK fails in getting the configuration of the server that the app currently runs on. Try calling the method again. | -| 305 | `AgoraChatErrorServerServingForbidden` | If the app is banned, the SDK returns this error code when the methods are called. | -| 400 | `AgoraChatErrorFileNotFound` | When the user is unable to get the log file or download the attachment, the SDK returns this error code. | -| 401 | `AgoraChatErrorFileInvalid` |When the uploaded message attachment or the shared file in the group is invalid, the SDK returns this error code. | -| 402 | `AgoraChatErrorFileUploadFailed` | When the message attachment cannot be uploaded, the SDK returns this error code. Try uploading again. | -| 403 | `AgoraChatErrorFileDownloadFailed` | When the message attachment cannot be downloaded, the SDK returns this error code. Try downloading again. | -| 404 | `AgoraChatErrorFileDeleteFailed` | When getting the log file, the SDK deletes the old log file. If the old log files cannot be deleted, the SDK returns this error code. | -| 405 | `AgoraChatErrorFileTooLarge` | When the size of the message attachment or the group shared file exceeds the limit, the SDK returns this error code. Adjust the file size, and try uploading again. | -| 406 | `AgoraChatErrorFileContentImproper` | This error can also be reported if you fail to upload a message attachment. | -| 500 | `AgoraChatErrorMessageInvalid` | The content of the message to be sent is empty, the message ID is empty, or the user ID of the sender is not the user ID that is currently logged in. Check the problems, and try sending the message again. | -| 502 | `AgoraChatErrorMessageTrafficLimit` | The message-sending frequency is too high or the message size is too large. Agora recommends reducing the sending frequency or the message size. | -| 504 | `AgoraChatErrorMessageRecallTimeLimit` | When a timeout occurs during message recall, the SDK returns this error code. | -| 505 | `AgoraChatErrorServiceNotEnable` | When you try using a service that is not enabled, the SDK returns this error code. | -| 506 | `AgoraChatErrorMessageExpired` | If you send a group receipt after the time limit (the default is three days), the SDK returns this error code. | -| 507 | `AgoraChatErrorMessageIllegalWhiteList` | If all members are banned in the group or chat room and the user ID is not included in the allow list, when this user tries sending a message, the SDK returns this error code. | -| 508 | `AgoraChatErrorMessageExternalLogicBlocked` |The sent message is intercepted by the user-defined pre-send callback rule. Check your settings of the pre-send callback rule. | -| 600 | `AgoraChatErrorGroupInvalidId` | When you call the methods related to the group and the group ID provided is invalid, the SDK returns this error code. | -| 601 | `AgoraChatErrorGroupAlreadyJoined` | When you call the group joining method, if the user has already joined the group, the SDK returns this error code. | -| 602 | `AgoraChatErrorGroupNotJoined` | When you try sending messages or controlling a group that you have not joined, the SDK returns this error code. | -| 603 | `AgoraChatErrorGroupPermissionDenied` | The user does not have permission to control the group, for example the group members do not have permission to set the group administrator. Check whether the user has administrator permissions. | -| 604 | `AgoraChatErrorGroupMembersFull` | The number of the group members has reached the limit. | -| 605 | `AgoraChatErrorGroupNotExist` | When you try controlling a group that does not exist, the SDK returns this error code. | -| 606 | `AgoraChatErrorGroupSharedFileInvalidId` | The group shared file ID is empty and the group shared file cannot be uploaded or downloaded. | -| 700 | `AgoraChatErrorChatroomInvalidId`| When you call the methods related to the chatroom and the chatroom ID provided is empty, the SDK returns this error code. | -| 701 | `AgoraChatErrorChatroomAlreadyJoined` | When you call the chatroom-joining method, if the user has already joined the chatroom, the SDK returns this error code. | -| 702 | `AgoraChatErrorChatroomNotJoined` | When you try sending messages or controlling a chatroom that you have not joined, the SDK returns this error code. | -| 703 | `AgoraChatErrorChatroomPermissionDenied` | The user does not have permission to control the chatroom, for example, the chatroom members do not have permission to set the chatroom administrator. Check whether the user has administrator permissions. | -| 704 | `AgoraChatErrorChatroomMembersFull` | The number of the chatroom members has reached the limit. | -| 705 | `AgoraChatErrorChatroomNotExist` | When you try controlling a chatroom that does not exist, the SDK returns this error code. | -| 900 | `AgoraChatErrorUserCountExceed` | When retrieving user attributes, if the number of the specified users exceed 100, the SDK returns this error code. | -| 901 | `AgoraChatErrorUserInfoDataLengthExceed` | The length of the set user attribute exceeds the limit. The sum of all user attributes for a single user cannot exceed 2 KB, and the sum of all user attributes for a single app cannot exceed 10 GB. | -| 903 | `AgoraChatErrorTranslateParamInvalid` | The parameters you are attempting to pass when calling APIs of the translation service are invalid. | -| 904 | `AgoraChatErrorTranslateFail` | The request to translate fails. | -| 905 | `AgoraChatErrorTranslateNotInit` | The translation service has not been initialized. | -| 1000 | `AgoraChatErrorContactAddFailed` | The request to add a contact fails. | -| 1001 | `AgoraChatErrorContactReachLimit` | You cannot add a contact because the number of your contacts has reached the limit. | -| 1002 | `AgoraChatErrorContactReachLimitPeer` | You cannot add a contact because the number of the peer contacts has reached the limit. | -| 1100 | `AgoraChatErrorPresenceParamExceed` | The length of the parameters you are attempting to pass in when calling APIs of the presence service exceed the limit. | -| 1101 | `AgoraChatErrorPresenceCannotSubscribeSelf` | You cannot subscribe to the presence status of yourself.| -| 1110 | `AgoraChatErrorTranslateParamError` | The parameters you are attempting to pass in when calling APIs of the translation service are invalid. | -| 1111 | `AgoraChatErrorTranslateServiceNotEnabled` | The translation service has not been activated. | -| 1112 | `AgoraChatErrorTranslateUsageLimit` | The usage of the translation service exceeds the limit. | -| 1113 | `AgoraChatErrorTranslateServiceFail` | The request to retrieve the translation service fails. | -| 1200 | `AgoraChatErrorModerationFailed` | The third-party content moderation service of Chat rates the message as "Reject". | +| 105 | `AgoraChatErrorUsernameTooLong` | The length of the user ID exceeds the limit of 64 bytes.| +| 108 | `AgoraChatErrorTokenExpire` | The token has expired. | +| 109 | `AgoraChatErrorTokeWillExpire` | The token has passed half of its validity period. | +| 110 | `AgoraChatErrorInvalidParam` | Invalid parameter. | +| 200 | `AgoraChatErrorUserAlreadyLoginSame` | The user has already logged in. | +| 201 | `AgoraChatErrorUserNotLogin` | The user hasn't logged in. For example, the login session is either invalid or has expired when a user requests to send a message or perform operations to a chat group. | +| 202 | `AgoraChatErrorUserAuthenticationFailed` | The user authentication fails because the token is invalid or has expired. | +| 203 | `AgoraChatErrorUserAlreadyExist` | The user ID specified during user account registration already exists. | +| 204 | `AgoraChatErrorUserNotFound` | The user does not exist. For example, the user ID specified for login or retrieval of the conversation list of a user does not exist. | +| 205 | `AgoraChatErrorUserIllegalArgument` | Incorrect user parameter. For example, the user ID specified during user account registration or user attribute updating is invalid or empty. | +| 206 | `AgoraChatErrorUserLoginOnAnotherDevice` | The user has logged in on another device. If the multi-device service is not enabled, the user is forced to log out of the current device upon successful login on another device with the same account. | +| 207 | `AgoraChatErrorUserRemoved` | The user account is deleted on the [Agora Console](https://console.agora.io/).| +| 209 | `AgoraChatErrorUpdateApnsConfigsFailed` | Fails to update the push configurations. For example, a failure of changing the nickname displayed for message push or updating do-not-disturb settings. | +| 210 | `AgoraChatErrorUserPermissionDenied` | The user has no permission to perform this operation. For example, a user that is banned attempts to send a message. | +| 213 | `AgoraChatErrorUserBindAnotherDevice` | The user has logged in to another device. This error occurs when a user has logged in on one device and try to log in on another one with the same account, if the app is configured to persist the login state on the current device while preventing the login on another device in a single-device login scenario. This error code is deprecated. | +| 214 | `AgoraChatErrorUserLoginTooManyDevices` | The user has reached the maximum number of devices on which he or she can log in with the same user account. This error occurs on a device with auto login enabled in a multi-device login scenario if the app turns on the switch of login on another device never kicking the user off on a current login device when the maximum number of login devices is exceeded. For example, a user can log in on at most four devices. At first, the user stays logged in on four devices, A (with auto login enabled), B, C, D. Then, the user gets logged out on device A due to network disruption and logs in on device E manually. After the network is available, auto login is performed on device A and fails due to the limit of login devices, triggering this error. | +| 215 | `AgoraChatErrorUserMuted` | The user is muted and not allowed to send messages in a chat group or chat room. | +| 216 | `AgoraChatErrorUserKickedByChangePassword` | The user has changed the login password. Once the login password is changed, the current login session ends and the user must log in again with the new password. | +| 217 | `AgoraChatErrorUserKickedByOtherDevice` | The user gets kicked off from a device in a multi-device login scenario on the [Agora Console](https://console.agora.io/) or by calling an API on another device. | +| 218 | `AgoraChatErrorUserAlreadyLoginAnother` | Another user has logged in. This error occurs if a user attempts to log in on the same device with another account before logging out on the device with the current account. | +| 219 | `AgoraChatErrorUserMutedByAdmin` | The user is muted globally and cannot send a message. | +| 220 | `AgoraChatErrorUserDeviceChanged` | The device on which a user attempts to log in is not the last one in a single-device login scenario. By default, if a user logs in on a another device, he or she will get kicked off from the current device in a single-device login scenario. This error occurs if the app turns on the switch of keeping the logged-in state on the current device if a user attempts to log in on another device. | +| 221 | `AgoraChatErrorUserNotOnRoster` | The user cannot send a message to another user that is not on the contact list. This error occurs if the switch of allowing message sending only between contacts is turned on. | +| 300 | `AgoraChatErrorServerNotReachable` | The server is not reachable. For example, the SDK is disconnected from the server due to unstable network conditions or other reasons when a user sends or recalls a message. | +| 301 | `AgoraChatErrorServerTimeout` | The request timeout. This error occurs when the server does not respond to an API request within the specified period, generally 30 or 60 seconds. | +| 302 | `AgoraChatErrorServerBusy` | The server is currently busy. Try again later. | +| 303 | `AgoraChatErrorServerUnknownError` | A common error for requests to the server. As this error occurs in multiple cases, the user needs to further identify and troubleshoot issues according to logs. | +| 304 | `AgoraChatErrorServerGetDNSConfigFailed` | The SDK fails in getting the configuration of the server that the app currently runs on. | +| 305 | `AgoraChatErrorServerServingForbidden` | The app is banned. This error occurs if a user tries to call a method when the app is banned. | +| 400 | `AgoraChatErrorFileNotFound` | The file is not found. For example, a log file is not found or downloading an attachment fails. | +| 401 | `AgoraChatErrorFileInvalid` | The file is invalid. For example, uploading a message attachment or a shared file in the group fails. | +| 402 | `AgoraChatErrorFileUploadFailed` | Fails to upload a file. For example, uploading a message attachment fails. | +| 403 | `AgoraChatErrorFileDownloadFailed` | Fails to download a file. For example, downloading a message attachment fails. | +| 404 | `AgoraChatErrorFileDeleteFailed` | Fails to delete the existing log file. When a user retrieves a new log file, the existing log file, if any, will be deleted before a new one is generated. | +| 405 | `AgoraChatErrorFileTooLarge` | The file is too large. For example, the message attachment or shared group file that a user attempts to upload exceeds the file size limit for upload. | +| 406 | `AgoraChatErrorFileContentImproper` | The file content is inappropriate. For example, a message attachment or shared group file fails to be uploaded because the file contains inappropriate contents. | +| 500 | `AgoraChatErrorMessageInvalid` | The message is invalid. For example, during message sending, the message object or message ID is empty, or the user ID of the message sender is inconsistent with the user ID of the current login session. | +| 502 | `AgoraChatErrorMessageTrafficLimit` | Messages are too large or sent too frequently. It is recommended that the user reduce the message sending frequency or the message size. | +| 504 | `AgoraChatErrorMessageRecallTimeLimit` | The message recall timeout. This error occurs when a message fails to be recalled because the timeout period expires. | +| 505 | `AgoraChatErrorServiceNotEnable` | The feature that the user is attempting to use is not enabled. This feature needs to be enabled on the [Agora Console](https://console.agora.io/) or by contacting [support@agora.io](mailto:support@agora.io) before it is ready to use. | +| 506 | `AgoraChatErrorMessageExpired` | The period for sending the read receipt for a group message has expired. The default validity period is 3 days. | +| 507 | `AgoraChatErrorMessageIllegalWhiteList` | The user is not on the allow list of a group or chat room. This error occurs when a user that is not on the allow list attempts to send a message in a chat group or chat room if all members of the group or chat room are muted. | +| 508 | `AgoraChatErrorMessageExternalLogicBlocked` | During the pre-sending callback, the message that the user is attempting to send is blocked by a message filtering rule defined in the app server. | +| 510 | `AgoraChatErrorMessageSizeLimit` | The body of the message to send exceeds the upper limit. | +| 511 | `AgoraChatErrorEditFailed` | Fails to modify a message. | +| 600 | `AgoraChatErrorGroupInvalidId` | Invalid group ID. For a group-related API, the chat group ID is an empty string or invalid. | +| 601 | `AgoraChatErrorGroupAlreadyJoined` | The user is already in this chat group. For example, the error occurs when a user attempts to join a chat group that he or she is already in. | +| 602 | `AgoraChatErrorGroupNotJoined` | The user hasn't joined this chat group. This error occurs when a user attempts to send a message or perform operations in a chat group that he or she is not in. | +| 603 | `AgoraChatErrorGroupPermissionDenied` | The user does not have the permission to perform the operation to a chat group. For example, a chat group member does not have permission to add or remove a chat group admin. | +| 604 | `AgoraChatErrorGroupMembersFull` | The number of members in the chat group has reached the upper limit specified during group creation. | +| 605 | `AgoraChatErrorGroupSharedFileInvalidId` | The group shared file ID is empty and the group shared file cannot be uploaded or downloaded. | +| 606 | `AgoraChatErrorGroupNotExist` | The chat group to which the user is requesting to perform operations does not exist.| +| 607 | `AgoraChatErrorGroupDisabled` | The chat group is disabled. | +| 608 | `AgoraChatErrorGroupNameViolation` | The chat group name is invalid. | +| 609 | `AgoraChatErrorGroupMemberAttributesReachLimit` | The number of custom attributes has reached the upper limit for a chat group member. | +| 610 | `AgoraChatErrorGroupMemberAttributesUpdateFailed` | Fails to set custom attributes for a chat group member. | +| 611 | `AgoraChatErrorGroupMemberAttributesKeyReachLimit` | The key of a custom attribute for a chat group member exceeds the limit of 16 bytes. | +| 612 | `AgoraChatErrorGroupMemberAttributesValueReachLimit` | The value of a custom attribute for a group member exceeds the limit of 512 bytes. | +| 700 | `AgoraChatErrorChatroomInvalidId`| Invalid chat room ID. This error occurs when the chat room ID is an empty string for the chat room-related method that is used. | +| 701 | `AgoraChatErrorChatroomAlreadyJoined` | The user is already in the chat room. This error occurs when a user attempts to join a chat room that he or she is already in. | +| 702 | `AgoraChatErrorChatroomNotJoined` | The user hasn't joined this chat room. This error occurs when a user attempts to send a message or perform operations in a chat room that he or she is not in. | +| 703 | `AgoraChatErrorChatroomPermissionDenied` | The user does not have the permission to perform the operation to a chat room. For example, a chat room member does not have permission to add or remove a chat room admin. | +| 704 | `AgoraChatErrorChatroomMembersFull` | The number of members in the chat room has reached the upper limit specified during chat room creation. | +| 705 | `AgoraChatErrorChatroomNotExist` | The chat room to which the user is requesting to perform operations does not exist. | +| 900 | `AgoraChatErrorUserCountExceed` | The number of users whose user attributes are to be retrieved exceeds 100. | +| 901 | `AgoraChatErrorUserInfoDataLengthExceed` | The user attributes are too long. The total length of all user attributes cannot exceed 2 KB for a user or 10 GB for an app. | +| 1000 | `AgoraChatErrorContactAddFailed` | Fails to add a contact. | +| 1001 | `AgoraChatErrorContactReachLimit` | The inviter has reached the maximum number of contacts that can be added. | +| 1002 | `AgoraChatErrorContactReachLimitPeer` | The invitee has reached the maximum number of contacts that can be added. | +| 1100 | `AgoraChatErrorPresenceParamExceed` | The length of a parameter in the presence-related API call exceeds the upper limit. | +| 1101 | `AgoraChatErrorPresenceCannotSubscribeSelf` | The user cannot subscribe to her or his own presence status. | +| 1110 | `AgoraChatErrorTranslateParamError` | Translation parameter error. | +| 1111 | `AgoraChatErrorTranslateServiceNotEnabled` | The translation service has not been enabled. The translation service needs to be enabled on the [Agora Console](https://console.agora.io/) before it is ready to use. | +| 1112 | `AgoraChatErrorTranslateUsageLimit` | The translation usage has reached the upper limit. | +| 1113 | `AgoraChatErrorTranslateServiceFail` | Fails to translate the message. | +| 1200 | `AgoraChatErrorModerationFailed` | The message moderation result provided by the third-party content moderation service is `Rejected`.| | 1299 | `AgoraChatErrorThirdServiceFailed` | Another service rather than the third-party content moderation service of Chat rates the message as "Reject". | -| 1300 | `AgoraChatErrorReactionReachLimit` | The number of reactions exceeds the limit. | -| 1301 | `AgoraChatErrorReactionHasBeenOperated` | The reaction to be added already exists in your reaction list. | -| 1302 | `AgoraChatErrorReactionOperationIsIllegal` | You do not have permission to perform operations to a reaction. For example, you cannot delete a reaction if the reaction does not exist in your reaction list. | +| 1300 | `AgoraChatErrorReactionReachLimit` | The number of Reactions for the message has reached the maximum allowed. | +| 1301 | `AgoraChatErrorReactionHasBeenOperated` | The user has added this Reaction and cannot add it repeatedly. | +| 1302 | `AgoraChatErrorReactionOperationIsIllegal` | The user does not have permission to operate on this Reaction. For example, a user that does not add this Reaction attempts to delete it or a user that is neither the message sender nor recipient tries to add a Reaction in a one-to-one chat. | | 1400 | `AgoraChatErrorThreadNotExist`| The thread does not exist. | -| 1401 | `AgoraChatErrorThreadAlreadyExist` | The thread to be created already exists in a chat group. | -| 1402 | `AgoraChatErrorThreadCreateMessageIllegal` | The request to send a message in a thread fails because the parent message of the thread is recalled. | +| 1401 | `AgoraChatErrorThreadAlreadyExist` | The thread to be created already exists. | +| 1402 | `AgoraChatErrorThreadCreateMessageIllegal` | The parent message for thread creation is invalid. For example, the message is recalled or unavailable. | +| 1500 | `AgoraChatErrorNotSupportPush` | The third-party push service is not supported. This error occurs if the configured third-party push service is not supported by the current device. | +| 1501 | `AgoraChatErrorPushBindFailed` | Fails to bind the device with the push token provided by a third-party push service. This error occurs when the token of a third-party push service fails to be uploaded to the server. | +| 1502 | `AgoraChatErrorPushUnBindFailed` | Fails to unbind the device from the push token provided by a third-party push service.| \ No newline at end of file diff --git a/shared/chat-sdk/reference/error-codes/web.mdx b/shared/chat-sdk/reference/error-codes/web.mdx index ab251c62a..d2f347840 100644 --- a/shared/chat-sdk/reference/error-codes/web.mdx +++ b/shared/chat-sdk/reference/error-codes/web.mdx @@ -7,63 +7,72 @@ During the run time of the Chat SDK, the error codes and error messages might be | Error code | Error message | Possible reason | | :----- | :-------------- | :----------------------------------------------------------- | -| 0 | `REQUEST_SUCCESS` | None. | +| 0 | `REQUEST_SUCCESS` | The operation succeeds. | | -1 | `REQUEST_TIMEOUT` | The request times out. | | -2 | `REQUEST_UNKNOWN` | An unidentified error occurs. | | -3 | `REQUEST_PARAMETER_ERROR` | The request parameters are invalid. | | -4 | `REQUEST_ABORT` | The request is aborted. | | 1 | `WEBIM_CONNCTION_OPEN_ERROR` | The request to retrieve a token fails. | -| 2 | `WEBIM_CONNCTION_AUTH_ERROR` | The SDK fails to verify the App Key. Try logging in again with a valid App Key. | +| 2 | `WEBIM_CONNCTION_AUTH_ERROR` | The App Key is invalid. The SDK fails to verify the App Key when the user calls a method. For how to get the App Key, see [Get the information of the Agora Chat project](../get-started/enable). | | 12 | `WEBIM_CONNCTION_GETROSTER_ERROR` | Fails to generate the token. | -| 16 | `WEBIM_CONNCTION_DISCONNECTED` | The WebSocket is disconnected due to network reasons. Try calling the method again. | -| 17 | `WEBIM_CONNCTION_AJAX_ERROR` | An unidentified error occurs. | -| 27 | `WEBIM_CONNCTION_APPKEY_NOT_ASSIGN_ERROR` | The App Key is invalid. Log in again using a valid App Key. For how to get the App Key, see [Get the information of the Chat project](/agora-chat/get-started/enable#get-the-information-of-the-agora-chat-project). | -| 28 | `WEBIM_CONNCTION_TOKEN_NOT_ASSIGN_ERROR` | The token entered to log in is empty or incorrect. Log in again using the correct token. | -| 31 | `WEBIM_CONNCTION_CALLBACK_INNER_ERROR` | An Internal error occurs when receiving the message callback. | -| 32 | `WEBIM_CONNCTION_CLIENT_OFFLINE` | If a user is not logged in or drops offline, when the user sends a message, the SDK returns this error. Log in and try sending the message. | -| 39 | `WEBIM_CONNECTION_CLOSED` | If a user is not logged in, or logged out, when the user sends a message, the SDK returns this error, Log in again and try sending the message. | +| 16 | `WEBIM_CONNCTION_DISCONNECTED` | The WebSocket is disconnected due to network reasons. | +| 17 | `WEBIM_CONNCTION_AJAX_ERROR` | A common error for requests to the server. | +| 27 | `WEBIM_CONNCTION_APPKEY_NOT_ASSIGN_ERROR` | The App Key is incorrect or not set. The error occurs during login. For how to get the App Key, see [Get the information of theAgora Chat project](./enable_agora_chat?platform=RESTful). | +| 28 | `WEBIM_CONNCTION_TOKEN_NOT_ASSIGN_ERROR` | The user fails to pass in the user token for login. | +| 31 | `WEBIM_CONNCTION_CALLBACK_INNER_ERROR` | An internal error in the message sending callback. | +| 32 | `WEBIM_CONNCTION_CLIENT_OFFLINE` | This error occurs if a user that is not logged in or gets offline attempts to send a message. | +| 39 | `WEBIM_CONNECTION_CLOSED` | The error occurs when a user that is logged out or not logged in attempts to send a message. The user needs to first log in before sending a message. | | 40 | `WEBIM_CONNECTION_ERROR` | The user authentication fails. | -| 50 | `MAX_LIMIT` | The number of reactions or the usage of translations has reached the limit. | -| 51 | `MESSAGE_NOT_FOUND` | The message to be reported does not exist. | +| 50 | `MAX_LIMIT` | The usage exceeds the service limit. For example, the number of Reactions that can be added for a message exceeds the upper limit; the maximum number of daily active users (DAU) or monthly active users (MAU) is exceeded. See the app limits of the current [pricing plan](https://docs.agora.io/en/agora-chat/reference/pricing-plan-details?platform=ios). | +| 51 | `MESSAGE_NOT_FOUND` | The message is not found. For example, the message to be reported is not found. | | 52 | `NO_PERMISSION` | The user has no permission to perform this operation. | -| 53 | `OPERATION_UNSUPPORTED` | The current operation is not supported. | -| 101 | `WEBIM_UPLOADFILE_ERROR` | The file upload fails because the message attachment or group file exceeds the file size limit. Adjust the file size, and try uploading again. | -| 102 | `WEBIM_UPLOADFILE_NO_LOGIN` | The user is not logged in when uploading the file, causing the file upload to fail. Log in and try uploading the file again. | -| 200 | `WEBIM_DOWNLOADFILE_ERROR` | When the message attachment cannot be downloaded, the SDK returns this error code. Try downloading the file again. | -| 204 | `USER_NOT_FOUND` | The user to be added to a chat group during chat group creation does not exist. | -| 206 | `WEBIM_CONNCTION_USER_LOGIN_ANOTHER_DEVICE` | If the user does not enable multi-device login, the user is forced to log out when logging in at another device, and the SDK returns this error code. | -| 207 | `WEBIM_CONNCTION_USER_REMOVED` | The logged in user is removed in the app background. | -| 216 | `WEBIM_CONNCTION_USER_KICKED_BY_CHANGE_PASSWORD` | If the logged in user changes the present password, the SDK kicks the user out and returns this error code. | -| 217 | `WEBIM_CONNCTION_USER_KICKED_BY_OTHER_DEVICE` | When the multi-device login function is enabled, if the user forces the user ID logged in at the current device to log out by calling APIs or managing the backend at another device, the SDK returns this error code. | -| 221 | `USER_NOT_FRIEND` | When a peer user sets not to receive messages from a user that is not a contact, if you send a message to this peer user, the SDK reports this error code. You can enable this feature on Agora Console. | +| 53 | `OPERATION_UNSUPPORTED` | The current operation is not supported. | +| 55 | `LOCAL_DB_OPERATION_FAILED` | The database operation fails. | +| 101 | `WEBIM_UPLOADFILE_ERROR` | Fails to upload the file. For example, the message attachment or group shared file to upload exceeds the file size limit for upload.| +| 102 | `WEBIM_UPLOADFILE_NO_LOGIN` | The user token is not contained in the file upload request. For example, the user is not logged in before uploading the file. | +| 200 | `WEBIM_DOWNLOADFILE_ERROR` | Fails to download a file due to timeout or a network failure. For example, a message attachment or shared file in a group fails to be downloaded. | +| 204 | `USER_NOT_FOUND` | The user is not found. For example, the user invited to join a chat group during group creation does not exist. | +| 205 | `MESSAGE_PARAMETER_ERROR` | Message parameter error. For example, the message ID is not set during message recall or the user ID of the message recipient is not passed in during message sending. | +| 206 | `WEBIM_CONNCTION_USER_LOGIN_ANOTHER_DEVICE` | The user has logged in on another device. If the multi-device service is not enabled, the user is forced to log out of the current device upon successful login on another device with the same account. | +| 207 | `WEBIM_CONNCTION_USER_REMOVED` | The user account is deleted on the [Agora Console](https://console.agora.io/). | +| 216 | `WEBIM_CONNCTION_USER_KICKED_BY_CHANGE_PASSWORD` | The user has changed the login password. Once the login password is changed, the current login session ends and the user must log in again with the new password. | +| 217 | `WEBIM_CONNCTION_USER_KICKED_BY_OTHER_DEVICE` | The user gets kicked off from a device in a multi-device login scenario on the [Agora Console](https://console.agora.io/) or by calling an API on another device.| +| 219 | `USER_MUTED_BY_ADMIN` | The user is muted globally and cannot send a message. | +| 221 | `USER_NOT_FRIEND` | The user cannot send a message to another user that is not on the contact list. This error occurs if the switch of allowing message sending only between contacts is turned on. | +| 500 | `SERVER_BUSY` | The server is busy. | +| 501 | `MESSAGE_INCLUDE_ILLEGAL_CONTENT` | The message contains inappropriate content. This error occurs when a message is found by the filtering system to contain inappropriate content. | +| 502 | `MESSAGE_EXTERNAL_LOGIC_BLOCKED` | The message is intercepted. This error occurs when a message is intercepted by the anti-spam service.| | 503 | `SERVER_UNKNOWN_ERROR` | The SDK fails to send the message due to an unknown error. | -| 504 | `MESSAGE_RECALL_TIME_LIMIT` | When a timeout occurs during message recall, the SDK returns this error code. | -| 505 | `SERVICE_NOT_ENABLED` | When you try using a service that is not enabled, the SDK returns this error code. Activate the service first and then call the method again. | -| 506 | `SERVICE_NOT_ALLOW_MESSAGING` | If all members are banned in the group or chat room and the user ID is not included in the allow list, when this user tries sending a message, the SDK returns this error code. | -| 507 | `SERVICE_NOT_ALLOW_MESSAGING_MUTE` | If the user is muted in the group or the chatroom, when the user sends a message, the SDK returns this error code. | -| 508 | `MESSAGE_MODERATION_BLOCKED` | The message is blocked by the moderation service. | -| 509 | `MESSAGE_CURRENT_LIMITING` | The number of group messages sent by a user has reached the rate limit. | -| 510 | `MESSAGE_WEBSOCKET_DISCONNECTED` | The network is disconnected, causing message sending failure. | -| 601 | `GROUP_ALREADY_JOINED` | The user to be added to a chat group already exists in the chat group. | -| 602 | `GROUP_NOT_JOINED` | When you try sending messages or controlling a group that you have not joined, the SDK returns this error code. | -| 603 | `PERMISSION_DENIED` | The user has no permission to operate. Check whether the user is banned. If the user is banned, unban the user and log in again. | -| 604 | `WEBIM_LOAD_MSG_ERROR` | An internal error occurs when receiving the callback and in the subsequent logic handling | -| 605 | `GROUP_NOT_EXIST` | When you try controlling a group that does not exist, the SDK returns this error code. | -| 606 | `GROUP_MEMBERS_FULL`| The number of chat group members has reached the limit. | -| 607 | `GROUP_NOT_EXIST` |The number of maximum chat group members that you are attempting to specify when creating a chat group exceeds the limit of your current pricing plan. | -| 700 | `REST_PARAMS_STATUS` | The token or app key is an empty string when calling RESTful APIs. | -| 702 | `CHATROOM_NOT_JOINED` | The user to whom you are requesting to perform operations does not exist in the chat room. | -| 704 | `CHATROOM_MEMBERS_FULL` | The number of chat room members has reached the limit. | +| 504 | `MESSAGE_RECALL_TIME_LIMIT` | The message recall timeout. This error occurs when a message fails to be recalled because the timeout period expires. | +| 505 | `SERVICE_NOT_ENABLED` | The feature that the user is attempting to use is not enabled. This feature needs to be enabled on the [Agora Console](https://console.agora.io/) or by contacting [support@agora.io](mailto:support@agora.io) before it is ready to use. | +| 506 | `SERVICE_NOT_ALLOW_MESSAGING` | The user is not on the allow list of a group or chat room. This error occurs when a user that is not on the allow list attempts to send a message in a chat group or chat room if all members of the group or chat room are muted. | +| 507 | `SERVICE_NOT_ALLOW_MESSAGING_MUTE` | The user is muted and not allowed to send messages in a chat group or chat room. | +| 508 | `MESSAGE_MODERATION_BLOCKED` | The message moderation result provided by the third-party content moderation service is `Rejected`. | +| 510 | `MESSAGE_WEBSOCKET_DISCONNECTED` | Fails to send the message due to the network disconnection. | +| 511 | `MESSAGE_SIZE_LIMIT` | The body of the message to send exceeds the upper limit. | +| 601 | `GROUP_ALREADY_JOINED` | The user is already in this chat group. For example, the error occurs when a user attempts to join a chat group that he or she is already in. | +| 602 | `GROUP_NOT_JOINED` | The user hasn't joined this chat group. The error occurs when a user attempts to send a message or perform operations in a chat group that he or she is not in. | +| 603 | `PERMISSION_DENIED` | The user does not have the permission to perform the operation to a chat group. For example, a chat group member does not have permission to add or remove a chat group admin. | +| 604 | `WEBIM_LOAD_MSG_ERROR` | An internal error in a message callback.| +| 605 | `GROUP_NOT_EXIST` | The chat group ID does not exist. For example, the chat group ID passed in to send a message does not exist. | +| 606 | `GROUP_MEMBERS_FULL`| The number of members in the chat group has reached the upper limit specified during group creation. | +| 607 | `GROUP_MEMBERS_LIMIT` |The maximum number chat group members that you are attempting to specify during group creation exceeds the [upper limit of your current pricing plan](https://docs.agora.io/en/agora-chat/reference/pricing-plan-details?platform=android#group). | +| 609 | GROUP_MEMBER_ATTRIBUTES_SET_FAILED | Fails to set custom attributes for a chat group member. | +| 700 | `REST_PARAMS_STATUS` | Fails to call an API because the user token or App Key does not exist or is incorrect. | +| 702 | `CHATROOM_NOT_JOINED` | The user to whom you are requesting to perform operations is not in the chat room. | +| 704 | `CHATROOM_MEMBERS_FULL` | The number of members in the chat room has reached the upper limit specified during chat room creation. | | 705 | `CHATROOM_NOT_EXIST` | The chat room to which you are requesting to perform operations does not exist. | -| 999 | `SDK_RUNTIME_ERROR` | A Websocket error occurs when sending a message. | -| 1100 | `PRESENCE_PARAM_EXCEED` | The length of the parameters you are passing in when calling APIs of the presence service exceeds the limit. | -| 1101 | `REACTION_ALREADY_ADDED` | The reaction to be added already exists in your reaction list. | -| 1102 | `REACTION_CREATING` |The reaction that you are attempting to create is being created by another user at the same time. | -| 1103 | `REACTION_OPERATION_IS_ILLEGAL` | You do not have permission to perform operations to a reaction. For example, you cannot delete a reaction if the reaction does not exist in your reaction list. | -| 1200 | `TRANSLATION_NOT_VALID` | The parameters you are passing in when calling APIs of the translation service are invalid. | -| 1201 | `TRANSLATION_TEXT_TOO_LONG` | The length of the source text to translate exceeds the limit. | -| 1204 | `TRANSLATION_FAILED` | The request to retrieve the translation service fails. | +| 999 | `SDK_RUNTIME_ERROR` | A Websocket error occurs when a user sends a message. | +| 1100 | `PRESENCE_PARAM_EXCEED` | The length of a parameter in the presence-related API call exceeds the upper limit. | +| 1101 | `REACTION_ALREADY_ADDED` | The user has added this Reaction and cannot add it repeatedly. | +| 1102 | `REACTION_CREATING` | The reaction that you are attempting to create is being created by another user at the same time. | +| 1103 | `REACTION_OPERATION_IS_ILLEGAL` | The user does not have permission to operate on this Reaction. For example, a user that does not add this Reaction attempts to delete it or a user that is neither the message sender nor recipient tries to add a Reaction in a one-to-one chat. | +| 1200 | `TRANSLATION_NOT_VALID` | The language code passed in by the user is invalid. | +| 1201 | `TRANSLATION_TEXT_TOO_LONG` | The length of the source text to translate exceeds the upper limit. | +| 1204 | `TRANSLATION_FAILED` | Fails to translate the message. | | 1300 | `THREAD_NOT_EXIST` | The thread does not exist. | -| 1301 | `THREAD_ALREADY_EXIST` | The thread to be created already exists. | +| 1301 | `THREAD_ALREADY_EXIST ` | The thread to be created already exists. | +| 1302 | `MODIFY_MESSAGE_NOT_EXIST` | The message to modify does not exist. | +| 1304 | `MODIFY_MESSAGE_FAILED` | Fails to modify a message. | \ No newline at end of file diff --git a/shared/chat-sdk/reference/error-codes/windows.mdx b/shared/chat-sdk/reference/error-codes/windows.mdx index 5231a03fa..453af61e9 100644 --- a/shared/chat-sdk/reference/error-codes/windows.mdx +++ b/shared/chat-sdk/reference/error-codes/windows.mdx @@ -26,71 +26,97 @@ SDKClient.Instance.Login(username, passwd, | Error code | Error message | Error description | | :----- | :--------------------------------------- | :----------------------------------------------------------- | | 0 | `EM_NO_ERROR` | The operation succeeds. | -| 1 | `GENERAL_ERROR` | The SDK is not properly initialized, or the server cannot identify this error. | +| 1 | `GENERAL_ERROR` | Default error related to the SDK or requests to the server. For example, the SDK is not properly initialized, or a request fails with no specific reason. | | 2 | `NETWORK_ERROR` | The SDK is disconnected from the server due to network interruption. | -| 4 | `EXCEED_SERVICE_LIMIT` | The usage exceeds the service limit. For example, the total number of registered user exceeds the limit of the current pricing plan. | -| 100 | `INVALID_APP_KEY` | The App Key is invalid. | -| 101 | `INVALID_USER_NAME` | The user ID is invalid. For example, when you request to add a contact, the username is set to an empty string. | -| 102 | `INVALID_PASSWORD` | The login password is empty or invalid. | -| 104 | `INVALID_TOKEN` | The login token is empty or invalid. | -| 105 | `USER_NAME_TOO_LONG` | The length of the username exceeds the limit of 64 bytes. | +| 3 | `DATABASE_ERROR` | The database operation fails. | +| 4 | `EXCEED_SERVICE_LIMIT` | The usage exceeds the service limit. For example, the total number of registered users or contacts exceeds the limit of the current [pricing plan](https://docs.agora.io/en/agora-chat/reference/pricing-plan-details?platform=ios). | +| 8 | `APP_ACTIVE_NUMBER_REACH_LIMITATION` | The app has reached its maximum number of daily active users (DAU) or monthly active users (MAU). | +| 100 | `INVALID_APP_KEY` | The App Key is invalid. For how to get the App Key, see [Get the information of the Agora Chat project](https://docs.agora.io/en/agora-chat/get-started/enable?platform=android#get-chat-project-information). | +| 101 | `INVALID_USER_NAME` | The user ID is invalid. For example, when a user requests to add a contact, the user ID is set to an empty string. | +| 102 | `INVALID_PASSWORD` | The login password is empty or invalid. | +| 104 | `INVALID_TOKEN` | The user token is empty or invalid. | +| 105 | `USER_NAME_TOO_LONG` | The length of the user ID exceeds the limit of 64 bytes. | 108 | `TOKEN_EXPIRED` | The token has expired. | | 109 | `TOKEN_WILL_EXPIRE` | The token has passed half of its validity period. | -| 200 | `USER_ALREADY_LOGIN` | The user has already logged in. | -| 201 | `USER_NOT_LOGIN` | The login session is either invalid or has expired when you request to send a message or perform operations to a chat group. | -| 202 | `USER_AUTHENTICATION_FAILED` | The user authentication fails because the token is either invalid or has expired. | -| 203 | `USER_ALREADY_EXIST` | When you register a user account, the specified user ID already exists. | -| 204 | `USER_NOT_FOUND` | When you request to log in as a user or retrieve the conversation list of a user, the specified user ID does not exist. | -| 205 | `USER_ILLEGAL_ARGUMENT` | When you request to register a user account or update user attributes, the specified user ID is invalid or empty. | -| 206 | `USER_LOGIN_ANOTHER_DEVICE` | If you have not enabled the multi-device service, you are forced to log out on one device by a login attempt on another device. | -| 207 | `USER_REMOVED` | Your account is deleted in the backend. | -| 208 | `USER_REG_FAILED` | The request to register a user account fails because the registration is closed. | -| 209 | `PUSH_UPDATECONFIGS_FAILED` | The nickname displayed during message push fails to be updated. | -| 210 | `USER_PERMISSION_DENIED` | You are blocked and not allowed to send messages. | -| 213 | `USER_BIND_ANOTHER_DEVICE` | If you set that the login device takes precedence, a login attempt on another device triggers this error to notify that this user has already logged in. | -| 214 | `USER_LOGIN_TOO_MANY_DEVICES` | The number of devices on which a user ID logs in exceeds the limit. | -| 215 | `USER_MUTED` | You are muted and not allowed to send messages in a chat group or chat room. | -| 216 | `USER_KICKED_BY_CHANGE_PASSWORD` | Once the password of a user account is updated, the current login session ends and you must log in again with the new password. | -| 217 | `USER_KICKED_BY_OTHER_DEVICE` | If you have enabled the multi-device service, you log out on one device by either a force quit API call on another device or a force quit operation in the backend. | -| 218 | `USER_ALREADY_LOGIN_ANOTHER` | Log in to the SDK with another user account while the current account has not been logged out. | -| 219 | `USER_MUTED_BY_ADMIN` | The App Key of a user is globally muted and not allowed to send messages. | -| 220 | `USER_DEVICE_CHANGED` | If you set that the login device takes precedence, a login attempt on another device triggers this error to notify that the login device is detected as irregular.| -| 221 | `USER_NOT_FRIEND` | If you set that only contacts can send messages to you in the console, the SDK returns this error when strangers attempt to send messages. | -| 300 | `SERVER_NOT_REACHABLE` | The SDK is disconnected from the server due to unstable networks when you send API requests. | -| 301 | `SERVER_TIMEOUT` | The server does not respond to an API request within the allocated period, generally 30 seconds or 60 seconds. | -| 302 | `SERVER_BUSY` | The server is busy. Retry later. | -| 303 | `SERVER_UNKNOWN_ERROR` | A default error is returned by the server. You need to further identify and troubleshoot this error with logs. | -| 304 | `SERVER_GET_DNSLIST_FAILED` | The SDK fails to retrieve the DNS server information. | -| 305 | `SERVER_SERVICE_RESTRICTED` | This error returns when the app server is restricted. | -| 400 | `FILE_NOT_FOUND` | The request to retrieve a log file or download an attachment fails. | -| 401 | `FILE_INVALID` | The request to upload a group shared file or message attachment fails. | -| 402 | `FILE_UPLOAD_FAILED` | The request to upload a message attachment fails. | -| 403 | `FILE_DOWNLOAD_FAILED` | The request to download a message attachment fails. | -| 404 | `FILE_DELETE_FAILED` | The outdated file fails to be deleted when retrieving the latest log file. | -| 405 | `FILE_TOO_LARGE` | The message attachment or shared group file you attempt to upload exceeds the limit of the file size. | -| 406 | `FILE_CONTENT_IMPROPER` | The content of a message attachment or shared group file does not meet the compliance requirements. | -| 500 | `MESSAGE_INVALID` | The request to send a message is invalid, for example, the message body or message ID is empty, or the user ID of the sender is inconsistent with the user ID of the current login session. | -| 501 | `MESSAGE_INCLUDE_ILLEGAL_CONTENT` | The message contains illegal content. | -| 502 | `MESSAGE_SEND_TRAFFIC_LIMIT` | Too many requests too often. Agora recommends that you reduce the call frequency or the message size. | -| 504 | `MESSAGE_RECALL_TIME_LIMIT` | A message cannot be recalled because the message exceeds the recall period. | -| 505 | `SERVICE_NOT_ENABLED` | The feature that you are attempting to use is not activated. Contact support@agora.io to activate this feature for your user account. | -| 506 | `MESSAGE_EXPIRED` | The chat group receipt has expired. The default valid period is 3 days. | -| 507 | `MESSAGE_ILLEGAL_WHITELIST` | You are not allowed to send messages because a chat group or chat room mutes all members and you are not on the allow list. | -| 508 | `MESSAGE_EXTERNAL_LOGIC_BLOCKED` | The message that you are attempting to send is blocked by the logic defined in your own server. | -| 600 | `GROUP_INVALID_ID` | The request to perform operations to a chat group fails because the chat group ID is an empty string. | -| 601 | `GROUP_ALREADY_JOINED` | The request to join a chat group fails because you have already joined the chat group. | -| 602 | `GROUP_NOT_JOINED` | The request to send a message or perform operations to a chat group fails because you have not joined the chat group. | -| 603 | `GROUP_PERMISSION_DENIED` | You do not have the privilege to perform the operation to a chat group. For example, a chat group member does not have permission to add or remove a chat group admin. | -| 604 | `GROUP_MEMBERS_FULL` | The number of chat group members exceeds the limit. | -| 605 | `GROUP_NOT_EXIST` | The chat group to which you are requesting to perform operations does not exist. | -| 700 | `CHATROOM_INVALID_ID` | The request to perform operations to a chat room fails because the chat room ID is an empty string. | -| 701 | `CHATROOM_ALREADY_JOINED` | The request to join a chat room fails because you have already joined the chat room. | -| 702 | `CHATROOM_NOT_JOINED` | The request to send a message or perform operations to a chat room fails because you have not joined the chat room. | -| 703 | `CHATROOM_PERMISSION_DENIED` | You do not have the privilege to perform the operation to a chat room. For example, a chat room member does not have permission to add or remove a chat room admin. | -| 704 | `CHATROOM_MEMBERS_FULL` | The number of chat room members exceeds the limit. | -| 705 | `CHATROOM_NOT_EXIST` | The chat room to which you are requesting to perform operations does not exist. | -| 900 | `PUSH_NOT_SUPPORT` | The third-party push service is not supported by the current device. | -| 901 | `PUSH_BIND_FAILED` | The token of the third-party push service fails to upload to the server. | -| 902 | `PUSH_UNBIND_FAILED` | The token of the third-party push service fails to unbind. | +| 110 | `INVALID_PARAM` | Invalid parameter. | +| 200 | `USER_ALREADY_LOGIN` | The user has already logged in. | +| 201 | `USER_NOT_LOGIN` | The user hasn't logged in. For example, the login session is either invalid or has expired when a user requests to send a message or perform operations to a chat group. | +| 202 | `USER_AUTHENTICATION_FAILED` | The user authentication fails because the token is invalid or has expired. | +| 203 | `USER_ALREADY_EXIST` | The user already exists: The user ID specified during user account registration already exists. | +| 204 | `USER_NOT_FOUND` | The user does not exist. For example, the user ID specified for login or retrieval of the conversation list of a user does not exist. | +| 205 | `USER_ILLEGAL_ARGUMENT` | Incorrect user parameter. For example, the user ID specified during user account registration or user attribute updating is invalid or empty. | +| 206 | `USER_LOGIN_ANOTHER_DEVICE` | The user has logged in on another device. If the multi-device service is not enabled, the user is forced to log out of the current device upon successful login on another device with the same account. | +| 207 | `USER_REMOVED` | The user account is deleted on the [Agora Console](https://console.agora.io/). | +| 210 | `USER_PERMISSION_DENIED` | The user has no permission to perform this operation. For example, a user that is banned attempts to send a message. | +| 213 | `USER_BIND_ANOTHER_DEVICE` | The user has logged in to another device. This error occurs when a user has logged in on one device and try to log in on another one with the same account, if the app is configured to persist the login state on the current device while preventing the login on another device in a single-device login scenario. This error code is deprecated.| +| 214 | `USER_LOGIN_TOO_MANY_DEVICES` | The user has reached the maximum number of devices on which he or she can log in with the same user account. This error occurs on a device with auto login enabled in a multi-device login scenario if the app turns on the switch of login on another device never kicking the user off on a current login device when the maximum number of login devices is exceeded. For example, a user can log in on at most four devices. At first, the user stays logged in on four devices, A (with auto login enabled), B, C, D. Then, the user gets logged out on device A due to network disruption and logs in on device E manually. After the network is available, auto login is performed on device A and fails due to the limit of login devices, triggering this error. | +| 215 | `USER_MUTED` | The user is muted and not allowed to send messages in a chat group or chat room. | +| 216 | `USER_KICKED_BY_CHANGE_PASSWORD` | The user has changed the login password. Once the login password is changed, the current login session ends and the user must log in again with the new password. | +| 217 | `USER_KICKED_BY_OTHER_DEVICE` | In a multi-device login scenario, the user gets kicked off from a device in on the [Agora Console](https://console.agora.io/) or by calling an API on another device. | +| 218 | `USER_ALREADY_LOGIN_ANOTHER` | Another user has logged in. This error occurs if a user attempts to log in on the same device with another account before logging out on the device with the current account. | +| 219 | `USER_MUTED_BY_ADMIN` | The user is muted globally and cannot send a message. | +| 220 | `USER_DEVICE_CHANGED` | The device on which a user attempts to log in is not the last one in a single-device login scenario. By default, if a user logs in on a another device, he or she will get kicked off from the current device in a single-device login scenario. This error occurs if the app turns on the switch of keeping the logged-in state on the current device if a user attempts to log in on another device. | +| 221 | `USER_NOT_FRIEND` | The user cannot send a message to another user that is not on the contact list. This error occurs if the switch of allowing message sending only between contacts is turned on. Agora Chat 有这个开关吗? | +| 300 | `SERVER_NOT_REACHABLE` | The server is not reachable. For example, the SDK is disconnected from the server due to unstable network conditions or other reasons when a user sends or recalls a message. | +| 301 | `SERVER_TIMEOUT` | The request timeout. This error occurs when the server does not respond to an API request within the specified period, generally 30 or 60 seconds. | +| 302 | `SERVER_BUSY` | The server is currently busy. Retry later. | +| 303 | `SERVER_UNKNOWN_ERROR` | A common error for requests to the server. As this error occurs in multiple cases, the user needs to further identify and troubleshoot issues according to logs. | +| 304 | `SERVER_GET_DNSLIST_FAILED` | The SDK fails in getting the configuration of the server that the app currently runs on. | +| 305 | `SERVER_SERVICE_RESTRICTED` | The app is banned. This error occurs if a user tries to call a method when the app is banned. | +| 400 | `FILE_NOT_FOUND` | The file is not found. For example, a log file is not found or downloading an attachment fails. | +| 401 | `FILE_INVALID` | The file is invalid. For example, uploading a message attachment or a shared file in the group fails. | +| 402 | `FILE_UPLOAD_FAILED` | Fails to upload a file. For example, uploading a message attachment fails. | +| 403 | `FILE_DOWNLOAD_FAILED` | Fails to download a file. For example, downloading a message attachment fails. | +| 404 | `FILE_DELETE_FAILED` | Fails to delete the existing log file. When a user retrieves a new log file, the existing log file, if any, will be deleted before a new one is generated. | +| 405 | `FILE_TOO_LARGE` | The file is too large. For example, the message attachment or shared group file that you attempt to upload exceeds the file size limit for upload. | +| 406 | `FILE_CONTENT_IMPROPER` | The file content is inappropriate. For example, a message attachment or shared group file fails to be uploaded because the file contains inappropriate contents. | +| 500 | `MESSAGE_INVALID` | The message is invalid. For example, during message sending, the message object or message ID is empty, or the user ID of the message sender is inconsistent with the user ID of the current login session. | +| 501 | `MESSAGE_INCLUDE_ILLEGAL_CONTENT` | The message contains inappropriate content. This error occurs when a message is found by the filtering system to contain inappropriate content. | +| 502 | `MESSAGE_SEND_TRAFFIC_LIMIT` | Messages are too large or sent too frequently. It is recommended that the user reduce the message sending frequency or the message size. | +| 504 | `MESSAGE_RECALL_TIME_LIMIT` | The message recall timeout. This error occurs when a message fails to be recalled because the timeout period expires. | +| 505 | `SERVICE_NOT_ENABLED` | The feature that the user is attempting to use is not enabled. This feature needs to be enabled on the [Agora Console](https://console.agora.io/) or by contacting [support@agora.io](mailto:support@agora.io) before it is ready to use. | +| 506 | `MESSAGE_EXPIRED` | The period for sending the read receipt for a group message has expired. The default validity period is 3 days. | +| 507 | `MESSAGE_ILLEGAL_WHITELIST` | The user is not on the allow list of a group or chat room. This error occurs when a user that is not on the allow list attempts to send a message in a chat group or chat room if all members of the group or chat room are muted. | +| 508 | `MESSAGE_EXTERNAL_LOGIC_BLOCKED` | During the pre-sending callback, the message that the user is attempting to send is blocked by a message filtering rule defined in the app server. | +| 510 | `MESSAGE_SIZE_LIMIT` | The body of the message to send exceeds the upper limit. | +| 511 | `MESSAGE_EDIT_FAILED` | Fails to modify a message. | +| 600 | `GROUP_INVALID_ID` | Invalid group ID. For a group-related API, the chat group ID is an empty string or invalid. | +| 601 | `GROUP_ALREADY_JOINED` | The user is already in this chat group. For example, the error occurs when a user attempts to join a chat group that he or she is already in.| +| 602 | `GROUP_NOT_JOINED` | The user hasn't joined this chat group. This error occurs when a user attempts to send a message or performs operations in a chat group that he or she is not in. | +| 603 | `GROUP_PERMISSION_DENIED` | The user does not have the permission to perform the operation to a chat group. For example, a chat group member does not have permission to add or remove a chat group admin. | +| 604 | `GROUP_MEMBERS_FULL` | The number of members in the chat group has reached the upper limit specified during group creation. | +| 605 | `GROUP_SHARED_FILE_INVALIDID` | The ID of the shared file in the chat group is invalid. | +| 606 | `GROUP_NOT_EXIST` | The chat group to which the user is requesting to perform operations does not exist. | +| 607 | `GROUP_DISABLED` | The chat group is disabled. | +| 608 | `GROUP_NAME_VIOLATION` | The chat group name is invalid. | +| 609 | `GROUP_MEMBER_ATTRIBUTES_REACH_LIMIT` | The number of custom attributes has reached the upper limit for a chat group member. | +| 610 | `GROUP_MEMBER_ATTRIBUTES_UPDATE_FAILED` | Fails to set custom attributes for a chat group member. | +| 611 | `GROUP_MEMBER_ATTRIBUTES_KEY_REACH_LIMIT` | The key of a custom attribute for a chat group member exceeds the limit of 16 bytes. | +| 612 | `GROUP_MEMBER_ATTRIBUTES_VALUE_REACH_LIMIT` | The value of a custom attribute for a group member exceeds the limit of 512 bytes. | +| 700 | `CHATROOM_INVALID_ID` | Invalid chat room ID. This error occurs when the chat room ID is an empty string for the chat room-related method that is used. | +| 701 | `CHATROOM_ALREADY_JOINED` | The user is already in the chat room. This error occurs when a user attempts to join a chat room that he or she is already in. | +| 702 | `CHATROOM_NOT_JOINED` | The user hasn't joined this chat room. This error occurs when a user attempts to send a message or perform operations in a chat room that he or she is not in. | +| 703 | `CHATROOM_PERMISSION_DENIED` | The user does not have the permission to perform the operation to a chat room. For example, a chat room member does not have permission to add or remove a chat room admin. | +| 704 | `CHATROOM_MEMBERS_FULL` | The number of members in the chat room has reached the upper limit specified during chat room creation. | +| 705 | `CHATROOM_NOT_EXIST` | The chat room to which the user is requesting to perform operations does not exist. | +| 900 | `USERINFO_USERCOUNT_EXCEED` | The number of users whose user attributes are to be retrieved exceeds 100. | +| 901 | `USERINFO_DATALENGTH_EXCEED` | The user attributes are too long. The total length of all user attributes cannot exceed 2 KB for a user or 10 GB for an app. | +| 1000 | `CONTACT_ADD_FAILED` | Fails to add a contact. | +| 1001 | `CONTACT_REACH_LIMIT` | The inviter has reached the maximum number of contacts that can be added. | +| 1002 | `CONTACT_REACH_LIMIT_PEER` | The invitee has reached the maximum number of contacts that can be added. | +| 1100 | `PRESENCE_PARAM_LENGTH_EXCEED` | The length of a parameter in the presence-related API call exceeds the upper limit. | +| 1101 | `PRESENCE_CANNOT_SUBSCRIBE_YOURSELF` | The user cannot subscribe to her or his own presence status. | +| 1110 | `TRANSLATE_PARAM_INVALID` | Translation parameter error. | +| 1111 | `TRANSLATE_SERVICE_NOT_ENABLE` | The translation service has not been enabled. The translation service needs to be enabled on the [Agora Console](https://console.agora.io/) before it is ready to use. | +| 1112 | `TRANSLATE_USAGE_LIMIT` | The translation usage has reached the upper limit. | +| 1113 | `TRANSLATE_MESSAGE_FAIL` | Fails to translate the message. | +| 1200 | `THIRD_MODERATION_FAILED` | The message moderation result provided by the third-party content moderation service is `Rejected`. | +| 1299 | `THIRD_DEFAULT_FAILED` | The content moderation result of another moderation service than the third-party service is `Rejected`. | +| 1300 | `REACTION_REACH_LIMIT` | The number of Reactions for the message has reached the maximum allowed. | +| 1301 | `REACTION_HAS_BEEN_OPERATED` | The user has added this Reaction and cannot add it repeatedly. | +| 1302 | `REACTION_OPERATION_IS_ILLEGAL` | The user does not have permission to operate on this Reaction. For example, a user that does not add this Reaction attempts to delete it or a user that is neither the message sender nor recipient tries to add a Reaction in a one-to-one chat. | +| 1400 | `THREAD_NOT_EXIST` | The thread does not exist. | +| 1401 | `THREAD_ALREADY_EXIST` | The thread to be created already exists. | +| 1402 | `THREAD_CREATE_MESSAGE_ILLEGAL` | The parent message for thread creation is invalid. For example, the message is recalled or unavailable. | | \ No newline at end of file diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index b989b7a51..7da883cba 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1469,7 +1469,7 @@ For the parameters and detailed descriptions, see [Common parameters](#param). | Parameter | Type | Required | Description | | :---------- | :------- | :------- | :----------------------------------------------------------- | | `msg_id` | String | Yes | The ID of the message to recall. As only one message can be recalled each time, you can pass in only one message ID. | -| `to` | String | No | The user, chat group, or chat room that receives the message to recall. You can specify a user ID, a chat group ID, or a chat room ID.
    **Note**: If the message to recall no longer exists on the server, only the message on the recipient client is recalled. | +| `to` | String | No | The user, chat group, or chat room that receives the message to recall. You can specify a user ID, a chat group ID, or a chat room ID. **Note**: If the message to recall no longer exists on the server, only the message on the recipient client is recalled. | | `chat_type` | String | Yes | The type of the chat where the message to recall is sent.
    • `chat`: An one-on-one chat.
    • `groupchat`: A chat group.
    • `chatroom`: A chat room.
    | | `from` | String | No | The user who recalls the message. By default, the recaller is the app admin. You can also specify another user as the recaller. | | `force` | bool | No | Whether to allow to recall messages beyond the storage time on the server. For details on the message storage duration on the server, see [Message storage duration](https://docs.agora.io/en/agora-chat/reference/limitations#message-storage-duration).
    • `true`: Yes. In this case, you can recall messages within the recall period or those beyond the storage time on the server. For the latter, this API recalls the messages locally saved by the recipient. If the message sending time is between your recall duration and the storage duration on the server, the recall fails. For example, if the recall duration is 2 minutes and the storage time on the server is 7 days, you can recall a message sent within 2 minutes or one that was sent more than 7 days ago; if the message is sent 3 minutes ago, the recall will fail.
    • `false`: No. You cannot recall messages beyond the storage time on the server. If you use the default recall time of 2 minutes or a custom duration, the server can only recall the messages sent within the specified time, and those beyond this time cannot be recalled. For example, if you set the recall time to 3 minutes and the message is sent 4 minutes ago, the recall will fail.
    | From d8c184464406bc1bb4d761cfc3ceb9340cb5af29 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 26 Oct 2023 21:22:32 +0300 Subject: [PATCH 10/37] Release notes --- .../reference/release-notes/android.mdx | 56 ++++++++++++++++ .../reference/release-notes/flutter.mdx | 52 ++++++++++++++ .../chat-sdk/reference/release-notes/ios.mdx | 45 +++++++++++++ .../reference/release-notes/react-native.mdx | 67 +++++++++++++++++++ .../reference/release-notes/unity.mdx | 64 ++++++++++++++++++ .../chat-sdk/reference/release-notes/web.mdx | 32 +++++++++ .../reference/release-notes/windows.mdx | 62 +++++++++++++++++ 7 files changed, 378 insertions(+) diff --git a/shared/chat-sdk/reference/release-notes/android.mdx b/shared/chat-sdk/reference/release-notes/android.mdx index e8ef912fe..4981bc812 100644 --- a/shared/chat-sdk/reference/release-notes/android.mdx +++ b/shared/chat-sdk/reference/release-notes/android.mdx @@ -1,5 +1,61 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `ChatMessage#createCombinedSendMessage`: Creates a combined message. + - `ChatManager#downloadAndParseCombineMessage`: Downloads and parses a combined message. +- Added the function of modifying sent messages: + - `ChatManager#asyncModifyMessage`: Modifies a sent text message. + - `MessageListener#onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the `ChatRoomManager#leaveChatRoom(String, CallBack)` method to leave a chat room and allow the user to know whether they successfully left the chat room. +- Added the function of pinning a conversation: + - `ChatManager#asyncPinConversation`: Pins a conversation. + - `ChatManager#asyncFetchPinnedConversationsFromServer`: Retrieves the list of pinned conversations from the server with pagination. +- Added the `ChatManager#asyncFetchConversationsFromServer` method to retrieve the conversation list from the server. Marked the `ChatManager#asyncFetchConversationsFromServer(int, int, EMValueCallBack)` method and the `ChatManager#asyncFetchConversationsFromServer(EMValueCallBack)` method deprecated. +- Added the `ChatManager#getAllConversationsBySort` method to retrieve local conversations in the reverse chronological order of when conversations are active. +- Added multi-device operations: + - `MultiDeviceListener#CONVERSATION_PINNED`: A conversation is pinned on one device. This event is received by other devices. + - `MultiDeviceListener#CONVERSATION_UNPINNED`: A conversation is unpinned on one device. This event is received by other devices. + - `MultiDeviceListener#CONVERSATION_DELETED`: A conversation is deleted from one device. This event is received by other devices. +- Added the `ChatManager#asyncFetchHistoryMessages` method to retrieve historical messages of a conversation from the server according to `FetchMessageOption`, the parameter configuration class for retrieving historical messages. +- Added `FetchMessageOption` as the parameter configuration class for retrieving historical messages from the server. +- Added the `Conversation#removeMessages` method to delete messages sent or received in a certain period from the local database. +- Added the `List` attribute in `MessageReactionChange`: + - `MessageReactionOperation#getUserId`: The user ID of the operator. + - `MessageReactionOperation#getReaction`: The changed Reaction. + - `MessageReactionOperation#getOperation`: The operation. +- Added the function of managing custom attributes of group members: + - `GroupManager#asyncSetGroupMemberAttributes`: Sets custom attributes of a group member. + - `GroupManager#asyncFetchGroupMemberAllAttributes`: Retrieves all custom attributes of a group member. + - `GroupManager#asyncFetchGroupMembersAttributes`: Retrieves custom attributes of multiple group members by attribute key. + - `GroupChangeListener#onGroupMemberAttributeChanged`: Occurs when a custom attribute is changed for a group member. + - `MultiDeviceListener#GROUP_METADATA_CHANGED`: Custom attributes are set for a group member on one device. This event is received by other devices. +- Added error codes: + - `Error#APP_ACTIVE_NUMBER_REACH_LIMITATION`: The number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. + - `Error#MESSAGE_SIZE_LIMIT`: You have exceeded the maximum allowed size of a message body. + - `Error#GROUP_MEMBER_ATTRIBUTES_REACH_LIMIT`: The total length of custom attributes of the group member has exceeded the upper limit (4 KB). + - `Error#GROUP_MEMBER_ATTRIBUTES_UPDATE_FAILED`: Fails to set the custom attribute(s) of the group member. + - `Error#GROUP_MEMBER_ATTRIBUTES_KEY_REACH_LIMIT`: The key of a custom attribute(s) of the group member has exceeded the maximum allowed length of 16 bytes. + - `Error#GROUP_MEMBER_ATTRIBUTES_VALUE_REACH_LIMIT`: The value of a custom attribute(s) of the group member has exceeded the maximum allowed length of 512 bytes. + +#### Improvements + +- Optimized the callback logic of `ChatClient#addConnectionListener`. After a connection listener is added, `ConnectionListener#onDisconnected` is triggered only after login. +- Optimized the `searchMsgFromDB` method to include custom messages in the search scope. +- Optimized the logic of binding and unbinding a push token. + +#### Issues fixed + +- The message read status is not updated in certain scenarios. +- In some scenarios, when the user calls `ChatManager#downloadAttachment` to download message attachments, the attachments are not downloaded to the private directory. +- When `ChatManager#deleteMessagesBeforeTimestamp` is called, messages in the local database are deleted, but those in the cache remain. +- The app crashes when you send a video message and set the first frame to be empty. + ## v1.1.0 v1.1.0 was released on April 28, 2023. diff --git a/shared/chat-sdk/reference/release-notes/flutter.mdx b/shared/chat-sdk/reference/release-notes/flutter.mdx index a8d8333cf..e5ff79174 100644 --- a/shared/chat-sdk/reference/release-notes/flutter.mdx +++ b/shared/chat-sdk/reference/release-notes/flutter.mdx @@ -1,5 +1,57 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `ChatManager#fetchCombineMessageDetail`:Retrieves the list of original messages included in a combined message from the server. +- Added the function of modifying sent messages: + - `ChatManager#modifyMessage`: Modifies a sent text message. + - `ChatEventHandler#onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the function of pinning a conversation: + - `ChatManager#pinConversation`: Pins or unpins a conversation. + - `ChatManager#fetchPinnedConversations`: Retrieves the list of pinned conversations from the server. +- Added the `fetchConversation` method to retrieve the conversation list from the server. Marked the `ChatManager#getConversationsFromServer` method deprecated. +- Added `FetchMessageOptions` as the parameter configuration class for retrieving historical messages from the server. +- Added the `ChatManager#fetchHistoryMessagesByOption` method to retrieve historical messages of a conversation from the server according to `FetchMessageOptions`, the parameter configuration class for retrieving historical messages. +- Added the `direction` parameter to `ChatManager#fetchHistoryMessages` to allow you to retrieve historical messages from the server according to the message search direction. +- Added the `ChatConversation#deleteMessagesWithTs` method to delete messages sent or received in a certain period from the local database. +- Added the function of managing custom attributes of group members: + - `ChatGroupManager#setMemberAttributes`: Sets custom attributes of a group member. + - `ChatGroupManager#fetchMemberAttributes` and `GroupManager#fetchMembersAttributes`: Retrieves custom attributes of group members. + - `ChatGroupEventHandler#onAttributesChangedOfGroupMember`: Occurs when a custom attribute is changed for a group member. +- Added the `reason` parameter to `ChatRoomEventHandler#onRemovedFromChatRoom` so that the member removed from the chat room knows the removal reason. +- Added the `ChatConnectionEventHandler#onAppActiveNumberReachLimit` callback that occurs when the number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. +- Added the `IMultiDeviceDelegate#OnRoamDeleteMultiDevicesEvent` callback that occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. +- Added the support for user tokens in the following methods: + - `ChatClient#fetchLoggedInDevices`: Retrieves the list of online login devices of a user. + - `ChatClient#kickDevice`: Kicks a user out of the app on a device. + - `ChatClient#kickAllDevices`: Kicks a user out of the app on all devices. +- Added the `ChatMultiDeviceEventHandler#onRemoteMessagesRemoved` callback that occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. +- Added the `List reactions` attribute in `ChatMessageReactionEvent`: + - `ReactionOperation#userId`: The user ID of the operator. + - `ReactionOperation#reaction`: The changed Reaction. + - `ReactionOperation#operate`: The operation. +- Added the `ChatRoomEventHandler#onSpecificationChanged` callback that occurs when details of a chat room are changed. + +#### Improvements + +- Optimized the `ChatManager#searchMsgFromDB` method to include custom messages in the message retrieval result. +- Adapted to the Android 14 system. + +#### Issues fixed + +- `ConnectionEventHandler#onConnected` and `ConnectionEventHandler#onDisconnected` cannot be received on the iOS system. +- Message extension attributes of the string type in the Android system turn into the Int type. +- Upon a hot reload on Android, the callback is triggered repeatedly. +- When you retrieve custom chat room attributes, passing `null` to the key of an attribute causes the app to crash. +- Chat room events cannot be received by a user that logs in to the Agora Chat server again after logout on the Android platform. +- `ChatManager#getThreadConversation` JSON error. +- `ChatMessage#chatThread` error. + ## v1.1.1 v1.1.1 was released on June 21, 2023. diff --git a/shared/chat-sdk/reference/release-notes/ios.mdx b/shared/chat-sdk/reference/release-notes/ios.mdx index 32b3a0153..f507fa2c0 100644 --- a/shared/chat-sdk/reference/release-notes/ios.mdx +++ b/shared/chat-sdk/reference/release-notes/ios.mdx @@ -1,5 +1,50 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `AgoraChatManager#downloadAndParseCombineMessage`: Downloads and parses a combined message. +- Added the function of modifying sent messages: + - `AgoraChatManager#modifyMessage`: Modifies a sent text message. + - `AgoraChatManagerDelegate#onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the function of pinning a conversation: + - `AgoraChatManager#pinConversation`: Pins a conversation. + - `AgoraChatManager#getPinnedConversationsFromServerWithCursor`: Retrieves the pinned conversations from the server. +- Added the `AgoraChatManager#getConversationsFromServerWithCursor` method to retrieve the conversation list from the server. +- Added the `AgoraChatManager#getAllConversations:` method to retrieve local conversations in the reverse chronological order of when conversations are active. +- Added `AgoraChatFetchServerMessagesOption` as the parameter configuration class for retrieving historical messages from the server. +- Added the `AgoraChatManager#fetchMessagesFromServerBy` method to retrieve historical messages of a conversation from the server according to `AgoraChatFetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. +- Added the `AgoraChatConversation#removeMessagesStart` method to delete messages sent or received in a certain period from the local database. +- Added the function of managing custom attributes of group members: + - `AgoraChatGroupManager#setMemberAttribute`: Sets custom attributes of a group member. + - `AgoraChatGroupManager#fetchMemberAttributes`: Retrieves custom attributes of group members. + - `AgoraChatGroupManagerDelegate#onAttributesChangedOfGroupMember`: Occurs when a custom attribute is changed for a group member. +- Added error codes: + - `AgoraChatErrorAppActiveNumbersReachLimitation`: The number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. + - `AgoraChatErrorMessageSizeLimit`: You have exceeded the maximum allowed size of a message body. + - `AgoraChatErrorGroupMemberAttributesReachLimit`: The total length of custom attributes of the group member has exceeded the upper limit (4 KB). + - `AgoraChatErrorGroupMemberAttributesUpdateFailed`: Fails to set the custom attribute(s) of the group member. + - `AgoraChatErrorGroupMemberAttributesKeyReachLimit`: The key of a custom attribute(s) of the group member has exceeded the maximum allowed length of 16 bytes. + - `AgoraChatErrorGroupMemberAttributesValueReachLimit`: The value of a custom attribute(s) of the group member has exceeded the maximum allowed length of 512 bytes. +- Added multi-device operations: + - `AgoraChatMultiDevicesEvent#AgoraChatMultiDevicesEventGroupMemberAttributesChanged`: Custom attributes are changed for a group member on one device. This event is received by other devices. + - `AgoraChatMultiDevicesEvent#AgoraChatMultiDevicesEventConversationPinned`: A conversation is pinned on one device. This event is received by other devices. + - `AgoraChatMultiDevicesEvent#AgoraChatMultiDevicesEventConversationUnpinned`: A conversation is unpinned on one device. This event is received by other devices. + - `AgoraChatMultiDevicesEvent#AgoraChatMultiDevicesEventConversationDelete`: A conversation is deleted from one device. This event is received by other devices. +- Added the `NSArray *operations` attribute in `AgoraChatMessageReactionChange`: + - `AgoraChatMessageReactionOperation#userId`: The user ID of the operator. + - `AgoraChatMessageReactionOperation#reaction`:The changed Reaction. + - `AgoraChatMessageReactionOperation#operate`:The Reaction operation. + +#### Improvements + +- Supported the ARM64 simulator on macOS. +- Optimized the `loadMessagesWithKeyword` method to include custom messages in the search scope. + ## v1.1.0 v1.1.0 was released on April 28, 2023. diff --git a/shared/chat-sdk/reference/release-notes/react-native.mdx b/shared/chat-sdk/reference/release-notes/react-native.mdx index 90637dc05..ecdf06801 100644 --- a/shared/chat-sdk/reference/release-notes/react-native.mdx +++ b/shared/chat-sdk/reference/release-notes/react-native.mdx @@ -1,5 +1,72 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Upgraded React-Native from 0.66.5 to 0.71.11. +- Added the function of forwarding multiple messages: + - `ChatMessage.createCombineMessage`: Creates a combined message. + - `ChatManager.fetchCombineMessageDetail`: Retrieves the original messages included in the combined message. +- Added the function of modifying sent messages. + - `ChatManager.modifyMessageBody`: Modifies a sent text message. + - `ChatEvents.ChatMessageEventListener.onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the `ChatManager.fetchConversationsFromServerWithCursor` method to retrieve the conversation list from the server with pagination. +- Added the function of pinning a conversation: + - `ChatManager.pinConversation`: Pins a conversation. + - `ChatManager.fetchPinnedConversationsFromServerWithCursor`: Retrieves a list of pinned conversations from the server. +- Added the `ChatManager.fetchConversationsFromServerWithCursor` method to retrieve the conversation list from the server. + Marked the `ChatManager.fetchAllConversations` method deprecated. +- Added the `ChatManager.fetchHistoryMessagesByOptions` method to retrieve historical messages of a conversation from the server according to `ChatFetchMessageOptions`, the parameter configuration class for pulling historical messages. +- Added `ChatFetchMessageOptions` as the parameter configuration class for pulling historical messages from the server. +- Added the function of managing custom attributes of group members: + - `ChatGroupManager.setMemberAttribute`: Sets custom attributes of a group member. + - `ChatGroupManager.fetchMemberAttributes`: Retrieves custom attributes of a group member from the server. + - `ChatGroupEventListener.onMemberAttributesChanged`: Occurs when a custom attribute is changed for a group member. +- Added the `ChatManager.deleteMessagesWithTimestamp` method to delete messages sent or received in a certain period from the local database. +- Added the `ChatOptions#enableEmptyConversation` option to determine whether to include empty conversations while loading conversations from the database. +- Added the `reason` parameter to `ChatRoomEventListener.onRemoved` so that the member removed from the chat room knows the removal reason. +- Added the `ChatPushManager.selectPushTemplate` method to allow the message recipient to receive offline message notifications according to the custom push template. +- Added the `ChatPushManager.fetchSelectedPushTemplate` method to retrieve the push template used for offline push notifications. +- Added the support for user tokens in the following methods: + - `ChatClient#getLoggedInDevicesFromServer`: Retrieves the list of online login devices of a user. + - `ChatClient#kickDevice`: Kicks a user out of the app on a device. + - `ChatClient.kickAllDevices`: Kicks a user out of the app on all devices. +- Added the log callback API `ChatLog.handler`. +- Added the `List` attribute in `onMessageReactionDidChange`: + - `MessageReactionOperation#getUserId`: The user ID of the operator. + - `MessageReactionOperation#getReaction`: The changed Reaction. + - `MessageReactionOperation#getOperation`: The operation. +- Added the following events: + - `ChatEvents.ChatConnectEventListener.onAppActiveNumberReachLimit`: Occurs when the number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. + - `ChatEvents.ChatConnectEventListener.onUserDidRemoveFromServer`: Occurs when the user is removed. + - `ChatEvents.ChatConnectEventListener.onUserDidForbidByServer`: Occurs when the user is blocked by the server. + - `ChatEvents.ChatConnectEventListener.onUserDidLoginTooManyDevice`: Occurs when the user's number of login devices exceeds the maximum allowed. + - `ChatEvents.ChatConnectEventListener.onUserKickedByOtherDevice`: Occurs when the user is kicked out of the app on the current device because the user has logged in to another device. + - `ChatEvents.ChatConnectEventListener.onUserAuthenticationFailed`: Occurs when the authentication fails. + - `ChatEvents.ChatMultiDeviceEventListener.onMessageRemoved`:Occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. + - `ChatEvents.ChatMultiDeviceEvent.CONVERSATION_PINNED`: Occurs when a conversation is pinned on one device. This event is received by other devices. + - `ChatEvents.ChatMultiDeviceEvent.CONVERSATION_UNPINNED`: Occurs when a conversation is unpinned on one device. This event is received by other devices. + - `ChatEvents.ChatMultiDeviceEvent.CONVERSATION_DELETED`: Occurs when a conversation is deleted on one device. This event is received by other devices. + +#### Improvements + +- Optimized disconnection notifications by showing an independent notification when the server breaks the connection to the app. In this case, the users can check the disconnection reason. +- Optimized git commit specifications with commitlint to make sure that the committed code follows the specifications. +- Optimized git commit with Lefthook by using Gitleaks to detect sensitive information. +- Renamed `ChatManager.deleteAllMessages` to `deleteConversationAllMessages`. +- Renamed `ChatEvents.ChatRoomEventListener.onRemoved` to `onMemberRemoved`. +- Renamed `ChatEvents.ChatGroupEventListener.onUserRemoved` to `onMemberRemoved`. +- Renamed `ChatEvents.ChatRoomEventListener.onChatRoomDestroyed` to `onDestroyed`. +- Renamed `ChatEvents.ChatGroupEventListener.onGroupDestroyed` to `onDestroyed`. +- Deleted the `errorCode` parameter from `ChatEvents.ChatConnectEventListener.onDisconnected`. + +#### Issues fixed + +The app crashes when a Reaction is added for a message on Android. + ## v1.1.3 v1.1.3 was released on July 21, 2023. diff --git a/shared/chat-sdk/reference/release-notes/unity.mdx b/shared/chat-sdk/reference/release-notes/unity.mdx index 19ef5d5e1..78436490f 100644 --- a/shared/chat-sdk/reference/release-notes/unity.mdx +++ b/shared/chat-sdk/reference/release-notes/unity.mdx @@ -1,5 +1,69 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `ChatMessage.createCombineMessage`: Creates a combined message. + - `ChatManager#FetchCombineMessageDetail`: Downloads and parses combined messages. + - `ChatManager.fetchCombineMessageDetail`: Retrieves the original messages included in the combined message.: + - `Message#CreateCombineSendMessage`: Creates a combined message. +- Added the function of modifying sent messages: + - `ChatManager#ModifyMessage`: Modifies a sent text message. + - `IChatManagerDelegate#OnMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the function of pinning a conversation: + - `ChatManager#PinConversation`: Pins a conversation. +- Added the `ChatManager#GetConversationsFromServerWithCursor` method to retrieve the conversation list from the server or retrieve the list of pinned conversations from the server. + Marked the `ChatManager#GetConversationsFromServer` method deprecated. +- Added `FetchServerMessagesOption` as the parameter configuration class for pulling historical messages from the server. +- Added the `ChatManager#FetchHistoryMessagesFromServerBy` method to retrieve historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for pulling historical messages. +- Added the `Conversation#DeleteMessages` method to delete messages sent or received in a certain period from the local database. +- Added the function of managing custom attributes of group members: + - `GroupManager#SetMemberAttributes`: Sets custom attributes of a group member. + - `GroupManager#FetchMemberAttributes`: Retrieves custom attributes of group members. + - `IGroupManagerDelegate#OnUpdateMemberAttributesFromGroup`: Occurs when a custom attribute is changed for a group member. +- Added the following options to the `Options` class: + - `Options#SDKDataPath`: Specifies the underlying storage path for SDK data. + - `Options#MyUUID`: Specifies a custom UUID for the current device. + - `Options#EnableEmptyConversation`: Determines whether to include empty conversations while loading conversations from the database. +- Added the `IConnectionDelegate#OnAppActiveNumberReachLimitation` callback that occurs when the number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. +- Added the `IMultiDeviceDelegate#OnRoamDeleteMultiDevicesEvent` callback that occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. +- Added the support for user tokens in the following methods: + - `SDKClient#GetLoggedInDevicesFromServerWithToken`: Retrieves the list of online login devices of a user. + - `SDKClient#KickDeviceWithToken`: Kicks a user out of the app on a device. + - `SDKClient#KickAllDevicesWithToken`: Kicks a user out of the app on all devices. +- Added multi-device operations: + - `MultiDevicesOperation#SET_METADATA`: Custom attributes of are set for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#DELETE_METADATA`: Custom attributes are deleted for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#GROUP_MEMBER_METADATA_CHANGED`: Custom attributes are changed for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_PINNED`: A conversation is pinned on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_UNPINNED`: A conversation is unpinned on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_DELETED`: A conversation is deleted from one device. This event is received by other devices. +- Added the `List` attribute in `MessageReactionDidChange`: + - `MessageReactionChange#ReactionList`: The changed Reaction list. + - `MessageReactionChange#OperationList`: The changed Reaction operation list. +- Added the error code `MESSAGE_SIZE_LIMIT` that is returned when the body of the message to be sent exceeds the upper limit. + +#### Improvements + +- Supported the ARM64 mode on macOS. +- Renamed `kickAllDevice` to `KickAllDevice`. +- Corrected misspellings in `MessageReaction`. +- Changed `Rection` to `Reaction`. +- Corrected misspellings in `MessageBody`: +- Changed `ThumbnaiRemotePath` to `ThumbnailRemotePath`. +- Changed `ThumbnaiSecret` to `ThumbnailSecret`. +- Changed `ThumbnaiDownStatus` to `ThumbnailDownStatus`. + +#### Issues fixed + +- The callback handler cannot be found when an SDK callback is triggered. +- The underlying resources are not released when the SDK is not initialized. +- The issues in user attribute updates on Android and iOS systems. + ## v1.1.3 v1.1.3 was released on October 2, 2023. diff --git a/shared/chat-sdk/reference/release-notes/web.mdx b/shared/chat-sdk/reference/release-notes/web.mdx index 55faaf6d0..5b569a6de 100644 --- a/shared/chat-sdk/reference/release-notes/web.mdx +++ b/shared/chat-sdk/reference/release-notes/web.mdx @@ -1,5 +1,37 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `downloadAndParseCombineMessage`: Downloads and parses a combined message. +- Added the function of modifying sent messages: + - `modifyMessage`: Modifies a sent text message. + - `onModifiedMessage`: Occurs when a sent message is modified. The message recipient receives this event. +- Added the function of pinning a conversation: + - `pinConversation`: Pins a conversation. + - `getServerPinnedConversations`: Retrieves the pinned conversations from the server. +- Added the `getServerConversations` method to retrieve the conversation list from the server. +- Added the `searchOptions` parameter object to the `getHistoryMessages` method for pulling historical messages from the server. +- Added the function of managing custom attributes of group members: + - `setGroupMemberAttributes`: Sets custom attributes of a group member. + - `getGroupMemberAttributes`: Retrieves custom attributes of group members. + - `GroupEvent#memberAttributesUpdate`: Occurs when a custom attribute is changed for a group member. +- Added the `MultiDeviceEvent#RoamingDeleteMultiDeviceInfo` event that occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. +- Added the `thumbnailHeight` and `thumbnailWidth` parameters to the `CreateImgMsgParameters` interface to allow you to send the image thumbnail size when sending an image message. +- Added the `isLast` field to the returned content of the `getHistoryMessages` method to indicates whether the returned data is on the last page. + +#### Improvements + +- The `addContact`, `acceptInvitation`, `declineInvitation`, `addToBlackList`, and `removeFromBlackList` methods support the Promise syntax. + +#### Issues fixed + +- A user, when pulling historical messages, sends a reception receipt to the server. + ## v1.1.0 v1.1.0 was released on April 28, 2023. diff --git a/shared/chat-sdk/reference/release-notes/windows.mdx b/shared/chat-sdk/reference/release-notes/windows.mdx index 890bf0d42..d42287bf8 100644 --- a/shared/chat-sdk/reference/release-notes/windows.mdx +++ b/shared/chat-sdk/reference/release-notes/windows.mdx @@ -1,5 +1,67 @@ +## v1.2.0 + +v1.2.0 was released on November XX, 2023. + +#### New features + +- Added the function of forwarding multiple messages: + - `ChatMessage.createCombineMessage`: Creates a combined message. + - `ChatManager#FetchCombineMessageDetail`: Downloads and parses combined messages. + - `ChatManager.fetchCombineMessageDetail`: Retrieves the original messages included in the combined message.: + - `Message#CreateCombineSendMessage`: Creates a combined message. +- Added the function of modifying sent messages: + - `ChatManager#ModifyMessage`: Modifies a sent text message. + - `IChatManagerDelegate#OnMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. +- Added the function of pinning a conversation: + - `ChatManager#PinConversation`: Pins a conversation. +- Added the `ChatManager#GetConversationsFromServerWithCursor` method to retrieve the conversation list from the server or retrieve the list of pinned conversations from the server. + Marked the `ChatManager#GetConversationsFromServer` method deprecated. +- Added `FetchServerMessagesOption` as the parameter configuration class for pulling historical messages from the server. +- Added the `ChatManager#FetchHistoryMessagesFromServerBy` method to retrieve historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for pulling historical messages. +- Added the `Conversation#DeleteMessages` method to delete messages sent or received in a certain period from the local database. +- Added the function of managing custom attributes of group members: + - `GroupManager#SetMemberAttributes`: Sets custom attributes of a group member. + - `GroupManager#FetchMemberAttributes`: Retrieves custom attributes of group members. + - `IGroupManagerDelegate#OnUpdateMemberAttributesFromGroup`: Occurs when a custom attribute is changed for a group member. +- Added the following options to the `Options` class: + - `Options#SDKDataPath`: Specifies the underlying storage path for SDK data. + - `Options#MyUUID`: Specifies a custom UUID for the current device. + - `Options#EnableEmptyConversation`: Determines whether to include empty conversations while loading conversations from the database. +- Added the `IConnectionDelegate#OnAppActiveNumberReachLimitation` callback that occurs when the number of daily active users (DAU) or monthly active users (MAU) for the app has reached the upper limit. +- Added the `IMultiDeviceDelegate#OnRoamDeleteMultiDevicesEvent` callback that occurs when historical messages in a conversation are deleted from the server on one device. This event is received by other devices. +- Added the support for user tokens in the following methods: + - `SDKClient#GetLoggedInDevicesFromServerWithToken`: Retrieves the list of online login devices of a user. + - `SDKClient#KickDeviceWithToken`: Kicks a user out of the app on a device. + - `SDKClient#KickAllDevicesWithToken`: Kicks a user out of the app on all devices. +- Added multi-device operations: + - `MultiDevicesOperation#SET_METADATA`: Custom attributes of are set for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#DELETE_METADATA`: Custom attributes are deleted for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#GROUP_MEMBER_METADATA_CHANGED`: Custom attributes are changed for a group member on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_PINNED`: A conversation is pinned on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_UNPINNED`: A conversation is unpinned on one device. This event is received by other devices. + - `MultiDevicesOperation#CONVERSATION_DELETED`: A conversation is deleted from one device. This event is received by other devices. +- Added the `List` attribute in `MessageReactionDidChange`: + - `MessageReactionChange#ReactionList`: The changed Reaction list. + - `MessageReactionChange#OperationList`: The changed Reaction operation list. +- Added the error code `MESSAGE_SIZE_LIMIT` that is returned when the body of the message to be sent exceeds the upper limit. + +#### Improvements + +- Renamed `kickAllDevice` to `KickAllDevice`. +- Corrected misspellings in `MessageReaction`. +- Changed `Rection` to `Reaction`. +- Corrected misspellings in `MessageBody`: +- Changed `ThumbnaiRemotePath` to `ThumbnailRemotePath`. +- Changed `ThumbnaiSecret` to `ThumbnailSecret`. +- Changed `ThumbnaiDownStatus` to `ThumbnailDownStatus`. + +#### Issues fixed + +- The callback handler cannot be found when an SDK callback is triggered. +- The transcoding issue of character sets handled by the SDK. + ## v1.1.0 v1.1.0 was released on April 28, 2023. From f3930bb9367c5c6f75b23b44274df6025c576b27 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Fri, 27 Oct 2023 16:01:05 +0300 Subject: [PATCH 11/37] Flutter release note updated --- shared/chat-sdk/reference/release-notes/flutter.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared/chat-sdk/reference/release-notes/flutter.mdx b/shared/chat-sdk/reference/release-notes/flutter.mdx index e5ff79174..144376bdd 100644 --- a/shared/chat-sdk/reference/release-notes/flutter.mdx +++ b/shared/chat-sdk/reference/release-notes/flutter.mdx @@ -51,6 +51,9 @@ v1.2.0 was released on November XX, 2023. - Chat room events cannot be received by a user that logs in to the Agora Chat server again after logout on the Android platform. - `ChatManager#getThreadConversation` JSON error. - `ChatMessage#chatThread` error. +- The `ChatRoomEventHandler#onSpecificationChanged` is not triggered when the chat room announcement changes. +- The Android platform crashes when a user is removed from a thread. +- An error occurs when `ChatThreadManager#fetchChatThreadMembers` is called. ## v1.1.1 From a805f8622521c1b21c558697f0dfffed2defd81c Mon Sep 17 00:00:00 2001 From: atovpeko Date: Wed, 1 Nov 2023 15:50:14 +0200 Subject: [PATCH 12/37] Review comments --- .../project-implementation/android.mdx | 56 +++++++++++++------ .../project-implementation/flutter.mdx | 31 ++++++---- .../project-implementation/ios.mdx | 13 ++--- .../project-implementation/react-native.mdx | 6 +- .../project-implementation/unity.mdx | 33 ++++++----- .../project-implementation/web.mdx | 5 +- .../project-implementation/windows.mdx | 35 +++++++----- shared/chat-sdk/reference/_limitations.mdx | 8 +-- 8 files changed, 116 insertions(+), 71 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 7eac09b6f..104b3ac13 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -1,23 +1,47 @@ -## Retrieve a list of conversations from the server +### Retrieve a list of conversations from the server -Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. +Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java -// pageNum: The current page number, starting from 1. -// pageSize: The number of conversations to get per page. The value range is [1,20]. -ChatClient.getInstance().chatManager().asyncFetchConversationsFromServer(pageNum, pageSize, new ValueCallBack>() { - // Add subsequent logic if retrieving conversation succeeds. - @Override - public void onSuccess(Map value) { - } - // Add subsequent logic if retrieving conversation fails. - @Override - public void onError(int error, String errorMsg) { - } -}); +String conversationId=" "; +Conversation.ConversationType type=Conversation.ConversationType.Chat; +FetchMessageOption option=new FetchMessageOption(); +//for example +//option.setIsSave(true); +int pageSize = 40; +String cursor = ""; +List messages = new ArrayList<>(); +doAsyncFetchHistoryMessages(conversationId,type,pageSize,cursor,option,messages); + +private void doAsyncFetchHistoryMessages(String conversationId, + Conversation.ConversationType type, + int pageSize,String cursor, + FetchMessageOption option, + List messages){ + ChatClient.getInstance().chatManager().asyncFetchHistoryMessages(conversationId, type, pageSize, cursor, option, new ValueCallBack>() { + @Override + public void onSuccess(CursorResult value) { + if (value != null ) { + List list = value.getData(); + if (list != null && list.size() > 0) { + messages.addAll(list); + } + String newCursor = value.getCursor(); + if( !TextUtils.isEmpty(newCursor)) { + doAsyncFetchHistoryMessages(conversationId, type, pageSize, newCursor, option, messages); + } + } + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); +} ``` If you still use the `asyncFetchConversationsFromServer` method to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). @@ -31,7 +55,7 @@ You can set the search direction to retrieve messages in the chronological or re If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index 43b63c81a..a617dfeb3 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -2,18 +2,27 @@ ### Retrieve a list of conversations from the server -Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. +Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```dart -try { - List list = - await ChatClient.getInstance.chatManager.fetchConversationListFromServer( - pageNum: pageNum, - pageSize: pageSize, - ); -} on ChatError catch (e) { -} +ChatConversationType conversationType = ChatConversationType.Chat; +FetchMessageOptions options = FetchMessageOptions( + from: senderId, + direction: ChatSearchDirection.Up, + startTs: 1695720454000, + endTs: 1695720554000, + needSave: false, +); + +ChatCursorResult result = + await ChatClient.getInstance.chatManager.fetchHistoryMessagesByOption( + conversationId, + conversationType, + options: options, + cursor: cursor, + pageSize: pageSize, +); ``` For users that do not support `fetchConversationListFromServer`, call `getConversationsFromServer` to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). @@ -24,7 +33,7 @@ After retrieving conversations, you can retrieve historical messages by paginati If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 991a18b5c..8a79271db 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -2,15 +2,14 @@ ### Retrieve a list of conversations from the server -Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. +Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```objective-c -// pageNum: The current page number, starting from 1. -// pageSize: The number of conversations to get per page. The value range is [1,20]. -[AgoraChatClient.sharedClient.chatManager getConversationsFromServerByPage:pageNum pageSize:pageSize completion:^(NSArray * _Nullable aConversations, AgoraChatError * _Nullable aError) { +AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOption alloc] init]; + [AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) { -}]; + }]; ``` For users that do not support `getConversationsFromServerByPage`, call `getConversationsFromServer` method to retrieve the conversations from the server, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). @@ -23,7 +22,7 @@ You can set the search direction to retrieve messages in the chronological or re If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 6d4c2524e..58124b793 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -2,8 +2,8 @@ ## Retrieve a list of conversations from the server -Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. +Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java // pageNum: The current page number, starting from 1. @@ -26,7 +26,7 @@ After retrieving conversations, you can retrieve historical messages by paginati If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index df6512480..da0757d0b 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -2,20 +2,27 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. Agora Chat server can store up to 3,000 conversation per end user. +Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp -SDKClient.Instance.ChatManager.GetConversationsFromServerWithPage(pageNum, pageSize, new ValueCallBack>( - // Add subsequent logics after retrieving the conversation. - // `list` is in the format of List. - onSuccess: (list) => - { - }, - onError: (code, desc) => - { - } -)); +FetchServerMessagesOption option = new FetchServerMessagesOption(); + option.IsSave = false; + option.Direction = MessageSearchDirection.UP; + option.From = "user"; + option.MsgTypes = new List(); + option.MsgTypes.Add(MessageBodyType.TXT); + option.MsgTypes.Add(MessageBodyTypeTime = 1695720454000; + option.EndTime = 1695720554000; + + SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( + onSuccess: (result) = > + { + } , + onError: (code, desc) = > + { + } + ) ) ; ``` For users that do not support `GetConversationsFromServerWithPage`, call `GetConversationsFromServer` to retrieve all the conversations from the server. By default, the SDK retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). @@ -26,7 +33,7 @@ After retrieving conversations, you can retrieve historical messages by paginati If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index abeda6d5e..403b5f483 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -2,8 +2,7 @@ ## Retrieve a list of conversations from the server -Call `getConversationlist` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. -Agora Chat server can store up to 3,000 conversation per end user. +Call `getConversationlist` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user.
    Do not use mixed upper-case.
    @@ -23,7 +22,7 @@ You can set the search direction to retrieve messages in the chronological or re If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 66c69ebc8..2294ded5e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -2,21 +2,28 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. -This retrieves up to 100 conversations per API call by default. Contact support@agora.io if you want to adjust this limit. -Agora Chat server can store up to 3,000 conversation per end user. +Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp -SDKClient.Instance.ChatManager.GetConversationsFromServerWithPage(pageNum, pageSize, new ValueCallBack>( - // Add subsequent logics after retrieving the conversation. - // `list` is in the format of List. - onSuccess: (list) => - { - }, - onError: (code, desc) => - { - } -)); +FetchServerMessagesOption option = new FetchServerMessageOption(); + option.IsSave = false; + option.Direction = MessageSearchDirection.UP; + option.From = "user"; + option.MsgTypes = new List(); + option.MsgTypes.Add(MessageBodyType.TXT); + option.MsgTypes.Add(MessageBodyType.VIDEO); + option.StartTime = 1695720454000; + option.EndTime = 1695720554000; + + SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( + onSuccess: (result) = > + { + }, + onError: (code, desc) = > + { + } + ) ) ; ``` For users that do not support `GetConversationsFromServerWithPage`, call `GetConversationsFromServer` to retrieve all the conversations from the server. By default, the SDK retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). @@ -27,7 +34,7 @@ After retrieving conversations, you can retrieve historical messages by paginati If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -Agora Chat servers only store up to 200 messages per Chat Group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index 06300c500..3d50f2b3b 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -56,17 +56,17 @@ Each chat room can have up to 100 custom attributes, and the total size of chat * End users can only forward up to 300 messages at a time. * The content of the forwarded messages can't be searched. * When forwarding multiple messages in a consolidated form, the title and preview of the combined message is displayed. The content of the message preview can't exceed 5KB. -* Applications developed with versions prioir to `1.2.x`` will not support display of forwarded messages. +* Applications developed with versions prior to `1.2.x` will not support display of forwarded messages. ### Sent message modification limitations This feature has the following limitations: -* End users can only edit messages sent by themselves and not others. +* For a group chat, regular group members can only edit message sent by themselves, but the group owner and admins can also edit messages sent by regular group members. The message sender remains unchanged regardless of the message edit operator. * Supported message types: text only. * Supported use case: One-on-one chat group. Does not support Chatroom. -* End users can recall and edit messages that were sent up to 7 days ago. -* Agora supports editing the same message up to 5 times. +* End users can recall and messages that were sent up to 7 days ago. +* Agora supports editing the same message up to 10 times. ### RESTful API Call limit of server-side From 50c8e34ff426106e68a80925c147e01a37ad2462 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 2 Nov 2023 13:36:37 +0200 Subject: [PATCH 13/37] Review comments --- .../messages/_send-receive-messages.mdx | 16 ---- .../project-implementation/android.mdx | 85 +++++++++++++++++++ .../reference/release-notes/flutter.mdx | 2 + .../chat-sdk/reference/release-notes/ios.mdx | 2 + .../chat-sdk/reference/release-notes/web.mdx | 2 + 5 files changed, 91 insertions(+), 16 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx index 51daab90e..7691b5554 100644 --- a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx +++ b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx @@ -25,22 +25,6 @@ This page shows how to implement sending, receiving, forwarding multiple message -**Forward multiple messages​** - - provides client APIs for forwarding multiple messages. Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. When a user receives a consolidated message with multiple forwarded messages, they can forward this message again, thus creating a layered message. This action can be performed up to 10 times. For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). - -**Modify sent messages​** - - provides client APIs that enable end users to edit messages after sending. Every end user or chat group member may edit messages that they have sent. The original message is recalled and a new messages is sent after editing. Once a message is recalled, it is purged from the message history stored on Agora's Chat servers. An edited message contains the following information: - -* The operator ID of the user performing the action. -* The operation time that indicates when the message was recalled and edited. -* The number of times a recalled message was edited (up to 5 times). -* The content of the most recent message. - -For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). - - ## Prerequisites Before proceeding, ensure that you meet the following requirements: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 879b943d9..80d10ffcc 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -338,4 +338,89 @@ ChatClient.getInstance().chatManager().sendMessage(message); message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attribute2", false) ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + +```java +ChatMessage message = ChatMessage.createCombinedSendMessage(title, summary, compatibleText, msgIds, toChatUsername); +//The chat type: ChatMessage.ChatType.Chat, ChatMessage.GroupChat, and ChatMessage.ChatRoom indicate one-to-one chat, group chat, and room chat respectively. +message.setChatType(ChatMessage.ChatType.Chat); +//Send the message +ChatClient.getInstance().chatManager().sendMessage(message); +``` + +```java +ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { + @Override + public void onSuccess(List value) { + + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); + +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. The original message is recalled and a new messages is sent after editing. Once a message is recalled, it is purged from the message history stored on Agora's Chat servers. Apart from the content changes, the edited message contains the following information: + +In the modified message, the message ID remains unchaged and only the message content is edited and the following items are added: operator ID, operation time, the number of modification times. + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was recalled and edited. +* The number of times a message is edited (up to 10 times). +* The modified message content. + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```java +String newContent="new content"; +TextMessageBody newTextMessageBody = new TextMessageBody(newContent); +ChatClient.getInstance().chatManager().asyncModifyMessage(targetMessage.getMsgId(), newTextMessageBody, new ValueCallBack() { +@Override +public void onSuccess(ChatMessage value) { + +} + +@Override +public void onError(int error, String errorMsg) { + +} +}); +``` + +```java +// Create a MessageListener object +MessageListener messageListener = new MessageListener() { + //…… + + @Override + public void onMessageContentChanged(ChatMessage messageModified, String operatorId, long operationTime) { + //int operationCount = messageModified.getBody().operationCount(); + // operatorId and operationTime can also be obtained as follows: + // String id = messageModified.getBody().operatorId(); + //long time = messageModified.getBody().operationTime(); + } + }; +//Register the messageListener +ChatClient.getInstance().chatManager().addMessageListener(messageListener); +//Remove the messageListener +ChatClient.getInstance().chatManager().removeMessageListener(messageListener); +``` + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/reference/release-notes/flutter.mdx b/shared/chat-sdk/reference/release-notes/flutter.mdx index 144376bdd..a40fa1d21 100644 --- a/shared/chat-sdk/reference/release-notes/flutter.mdx +++ b/shared/chat-sdk/reference/release-notes/flutter.mdx @@ -8,6 +8,8 @@ v1.2.0 was released on November XX, 2023. - Added the function of forwarding multiple messages: - `ChatManager#fetchCombineMessageDetail`:Retrieves the list of original messages included in a combined message from the server. + - `MessageType.COMBINE`: The combined message type. + - `CombineMessageBody`: The combined message body class. - Added the function of modifying sent messages: - `ChatManager#modifyMessage`: Modifies a sent text message. - `ChatEventHandler#onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. diff --git a/shared/chat-sdk/reference/release-notes/ios.mdx b/shared/chat-sdk/reference/release-notes/ios.mdx index f507fa2c0..7ce01dafa 100644 --- a/shared/chat-sdk/reference/release-notes/ios.mdx +++ b/shared/chat-sdk/reference/release-notes/ios.mdx @@ -8,6 +8,8 @@ v1.2.0 was released on November XX, 2023. - Added the function of forwarding multiple messages: - `AgoraChatManager#downloadAndParseCombineMessage`: Downloads and parses a combined message. + - `AgoraChatMessageBodyTypeCombine`: The combined message type. + - `AgoraChatCombineMessageBody`: The combined message body class. - Added the function of modifying sent messages: - `AgoraChatManager#modifyMessage`: Modifies a sent text message. - `AgoraChatManagerDelegate#onMessageContentChanged`: Occurs when a sent message is modified. The message recipient receives this callback. diff --git a/shared/chat-sdk/reference/release-notes/web.mdx b/shared/chat-sdk/reference/release-notes/web.mdx index 5b569a6de..9e99cc728 100644 --- a/shared/chat-sdk/reference/release-notes/web.mdx +++ b/shared/chat-sdk/reference/release-notes/web.mdx @@ -8,6 +8,8 @@ v1.2.0 was released on November XX, 2023. - Added the function of forwarding multiple messages: - `downloadAndParseCombineMessage`: Downloads and parses a combined message. + - `CreateCombineMsgParameters`: The properties of creating a combined message. + - `CombineMsgBody`: The combined message body type. - Added the function of modifying sent messages: - `modifyMessage`: Modifies a sent text message. - `onModifiedMessage`: Occurs when a sent message is modified. The message recipient receives this event. From a78c78e35803d44b59ebc13fb8ce9eb5f20655ea Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 2 Nov 2023 21:36:12 +0200 Subject: [PATCH 14/37] review comments --- .../project-implementation/android.mdx | 7 +- .../project-implementation/flutter.mdx | 61 ++++++++++++ .../project-implementation/ios.mdx | 59 ++++++++++++ .../project-implementation/react-native.mdx | 75 +++++++++++++++ .../project-implementation/unity.mdx | 85 +++++++++++++++++ .../project-implementation/web.mdx | 93 +++++++++++++++++++ .../project-implementation/windows.mdx | 86 +++++++++++++++++ .../chat-sdk/develop/_content-moderation.mdx | 2 +- .../agora-analytics/_data-metrics.mdx | 2 +- .../_user-attributes-management.mdx | 13 +++ 10 files changed, 476 insertions(+), 7 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 80d10ffcc..3eeb7d055 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -375,14 +375,11 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. The original message is recalled and a new messages is sent after editing. Once a message is recalled, it is purged from the message history stored on Agora's Chat servers. Apart from the content changes, the edited message contains the following information: - -In the modified message, the message ID remains unchaged and only the message content is edited and the following items are added: operator ID, operation time, the number of modification times. +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. -* The operation time that indicates when the message was recalled and edited. +* The operation time that indicates when the message was edited. * The number of times a message is edited (up to 10 times). -* The modified message content. For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 1e2cb66b1..64d04e39a 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -276,4 +276,65 @@ ChatClient.getInstance.chatManager.addEventHandler( ); ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + +```dart +String title = "Historical messages for one-to-one chats between A and B"; +String summary = + "A: These are historical messages from A. \nB: These are historical messages from B."; +String compatibleText = + "Your current version does not support this type of message. Please upgrade to the latest version."; +final msg = ChatMessage.createCombineSendMessage( + targetId: targetId, + msgIds: msgIds, + title: title, + summary: summary, + compatibleText: compatibleText, +); +await ChatClient.getInstance.chatManager.sendMessage(msg); +``` + +```dart +List list = + await ChatClient.getInstance.chatManager.fetchCombineMessageDetail( + message: combineMessage, +); +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```dart +ChatTextMessageBody body = ChatTextMessageBody(content: "new content"); +await ChatClient.getInstance.chatManager.modifyMessage( + messageId: msgId, + msgBody: body, +); +``` + +```dart +ChatEventHandler( + onMessageContentChanged: (message, operatorId, operationTime) {}, +) +``` + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 17d7029dc..91a05ac05 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -357,4 +357,63 @@ message.chatType = AgoraChatTypeChat; } ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + +```objective-c +AgoraChatCombineMessageBody *body = [[AgoraChatCombineMessageBody alloc] initWithTitle:@"Chat History" summary:@"summary" compatibleText:@"The version is low and unable to display the content." messageIdList:@[@"messageId1",@"messageId2"]]; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:@"conversationId" body:body ext:nil]; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:^(AgoraChatMessage *aMessage, AgoraChatError *aError) { + +}]; +``` + +```objective-c +- (void)messagesDidReceive:(NSArray *)aMessages +{ + for(AgoraChatMessage* msg in aMessages) { + if (msg.body.type == AgoraChatMessageBodyTypeCombine) { + [AgoraChatClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, AgoraChatError * _Nullable error) { + + }]; + } + } +} +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```ObjectiveC +AgoraChatTextMessageBody* newBody = [[AgoraChatTextMessageBody alloc] initWithText:@"new content"]; + [AgoraChatClient.sharedClient.chatManager modifyMessage:msgId body:newBody completion:^(AgoraChatError * _Nullable error, AgoraChatMessage * _Nullable message) { + + }]; +``` + +```ObjectiveC +- (void)onMessageContentChanged:(AgoraChatMessage *)message operatorId:(NSString *)operatorId operationTime:(NSUInteger)operationTime { + +} +``` + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). + +
    \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index b7b4d8027..140b90cdc 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -206,4 +206,79 @@ You can also use `ChatMessageEventListener` to listen for the state of recalling onMessagesRecalled(messages: ChatMessage[]): void; ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + +```typescript +// Construct a combined message. +const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { + title, + summary, + compatibleText, +}); +EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); +``` + +```typescript +// message: The combined message object. +// Asynchronously return the list of original messages. +ChatClient.getInstance() + .chatManager.fetchCombineMessageDetail(message) + .then((messages: ChatMessage[]) => { + console.log("success: ", messages); + }) + .catch((error) => { + console.log("fail: ", error); + }); +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```typescript +ChatClient.getInstance() + .chatManager.modifyMessageBody(msgId, body) + .then((message) => { + console.log("modify success:", message); + }) + .catch((error) => { + console.warn(error); + }); +``` + +```typescript +ChatClient.getInstance().chatManager.addMessageListener({ + onMessageContentChanged: ( + message: ChatMessage, + lastModifyOperatorId: string, + lastModifyTime: number + ): void => { + console.log( + `${QuickTestScreenChat.TAG}: onMessageContentChanged: `, + JSON.stringify(message), + lastModifyOperatorId, + lastModifyTime + ); + }, +} as ChatMessageEventListener); +``` + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index b93bdca61..65117c52a 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -399,4 +399,89 @@ if (found) { } ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + + +```csharp +String title = "Historical messages for one-to-one chats between A and B"; +String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; +String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; +Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); + +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + // Handling logic upon the success of sending the message + }, + onError: (code, desc) => { + // Handling logic upon a failure in sending the message + } +)) ; +``` + +```csharp +SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) = > { + // Add the handling logic and show the message list + } , + onError: (code, desc) = > { + // Handle an error + } + ) ) ; +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) = > + { + } , + onError: (code, desc) = > + { + } + )) ; +``` + +```csharp +// Inherit and implement `IChatManagerDelegate`. +public class ChatManagerDelegate : IChatManagerDelegate { + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime in the following way: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + +// Add a delegate. + +ChatManagerDelegate adelegate = new ChatManagerDelegate(); + +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +// Remove the delegate when it is unnecessary. +SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); +``` + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index dfb020901..b21037d43 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -502,4 +502,97 @@ function sendPrivateText() { } ``` +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + + +```javaScript +let option = { + chatType: "singleChat", + type: "combine", + to: "userId", + compatibleText: "Your SDK does not support combined messages. Please upgrade.", + title: "Chat history", + summary: "hi", + messageList: [ + // message body + { + type: "txt", + chatType: "singleChat", + // ... + }, + ], + onFileUploadComplete: (data) => { + option.url = data.url; + }, +}; +let msg = AC.message.create(option); +connection.send + .send(msg) + .then((res) => { + console.log("Succeeded in sending the message", res); + }) + .catch((err) => { + console.log("Failed to send the message", err); + }); + +``` + +```javaScript +connection + .downloadAndParseCombineMessage({ + url: msg.url, + secret: msg.secret, + }) + .then((res) => { + console.log("The list of original messages obtained after parsing", res); + }); +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```javaScript +// Adds the message modification event +connection.addEventHandler("modifiedMessage", { + onModifiedMessage: message => { + console.log('onModifiedMessage', message) + }, +}); + +const textMessage = AC.message.create({ + type: 'txt', + msg: 'message content', + to: 'username', + chatType: 'singleChat', +}); + +connection.modifyMessage({ messageId: 'messageId', modifiedMessage: textMessage }) + .then((res) => { + console.log(res.message) + }) + .catch((e) => { + console.log(e) + }); +``` + + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index a40372a00..0f3ece57d 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -399,4 +399,90 @@ if (found) { // Use variable b. } ``` + +### Forward multiple messages + +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. + +The process of sending and receiving a consolidated message is as follows: + +1. The sender creates a consolidated message with a list of original messages. +1. The sender sends the consolidated message. +1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. + +```csharp +String title = "Historical messages for one-to-one chats between A and B"; +String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; +String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; +Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + o nSuccess: () = > { + // Handling logic upon the success of sending the message + } , + onError: (code, desc) = > { + // Handling logic upon a failure in sending the message + } + ) ) ; +``` + + +```csharp + +SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) = > { + // Add the handling logic and show the message list + } , + onError: (code, desc) = > { + // Handle an error + } +)) ; +``` + +For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). + +### Modify sent messages + +Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: + +* The operator ID of the user performing the action. +* The operation time that indicates when the message was edited. +* The number of times a message is edited (up to 10 times). + +For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. + +```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) = > + { + } , + onError: (code, desc) = > + { + } + ) ) ; +``` + +```csharp + +// Inherit and implement `IChatManagerDelegate`. + public class ChatManagerDelegate : IChatManagerDelegate { + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime in the following way: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + +// Add a delegate. +ChatManagerDelegate adelegate = new ChatManagerDelegate(); +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +// Remove the delegate when it is unnecessary. +SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); +``` + + +For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). +
    \ No newline at end of file diff --git a/shared/chat-sdk/develop/_content-moderation.mdx b/shared/chat-sdk/develop/_content-moderation.mdx index b67800cf8..bb05b7e7c 100644 --- a/shared/chat-sdk/develop/_content-moderation.mdx +++ b/shared/chat-sdk/develop/_content-moderation.mdx @@ -57,7 +57,7 @@ Powered by [Microsoft Azure Moderator](https://azure.microsoft.com/en-us/service - Adult: The content may be considered sexually explicit or adult in certain situations. - Mature: The content may be considered sexually suggestive or mature in certain situations. - Offensive: The content may be considered offensive or abusive. -- Personal Data: The content includes personally identifiable information. +- Personal Data: The content contains personally identifiable information, which includes email address, US mailing address, IP address, and a US phone number. Please note that content moderation will determine an input to be a US mailing address only if the input contains all elements of a mailing address (e.g., zip code, state abbreviation). After enabling the text and image moderation feature on Agora Console, you can set a sensitivity threshold for each moderation category. If the sensitivity threshold is exceeded, Agora Chat will handle the message as specified in the moderation rule. A greater sensitivity indicates more strict review and that Agora Chat will block more inappropriate content. You are advised to test the moderation rule to check whether the sensitivity threshold you set meets your requirements. diff --git a/shared/chat-sdk/reference/agora-analytics/_data-metrics.mdx b/shared/chat-sdk/reference/agora-analytics/_data-metrics.mdx index 0339c92ba..0b0143e81 100644 --- a/shared/chat-sdk/reference/agora-analytics/_data-metrics.mdx +++ b/shared/chat-sdk/reference/agora-analytics/_data-metrics.mdx @@ -6,7 +6,7 @@ This page explains Chat-related metrics. ### Total registered users -The number of registered users under this project as of the current time. +The accumulated number of registered users under this project as of the current time. This number could decline if some UIDs are deleted. ### Daily new users diff --git a/shared/chat-sdk/restful-api/_user-attributes-management.mdx b/shared/chat-sdk/restful-api/_user-attributes-management.mdx index 47722a3f8..8742cb9fd 100644 --- a/shared/chat-sdk/restful-api/_user-attributes-management.mdx +++ b/shared/chat-sdk/restful-api/_user-attributes-management.mdx @@ -73,6 +73,19 @@ The request body is in the format of JSON String, and the length cannot exceed 4 | `Key` | String | Attribute name | Yes | | `Value` | String | Attribute value | Yes | +When you call this RESTful API to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass in the following keys to make sure that the client can obtain the settings from the server: + +| Field | Type | Description | +|---|---|---| +| nickname | String | The user nickname, which can contain at most 64 characters. | +| avatarurl | String | The user avatar URL, which can contain at most 256 characters. | +| phone | String | The user's phone number, which can contain at most 32 characters. | +| mail | String | The user's email address, which can contain at most 64 characters. | +| gender | Number | The user gender: 1:Male; 2:Female; (Default) 0: Unknown; Other values are invalid. | +| sign | String | The user's signature, which can contain at most 256 characters. | +| birth | String | The user's birthday, which can contain at most 256 characters. | +| ext | String | The extension fields. | + ### HTTP response #### Response body From e68fc92f4079c758daebe8d56e00ceff84965b7e Mon Sep 17 00:00:00 2001 From: Dasun Nirmitha Date: Fri, 3 Nov 2023 03:19:58 +0530 Subject: [PATCH 15/37] Chat 1.2 Document new features added in October 2023 - iOS changes --- .../manage-group-member-attributes.mdx | 13 +++++++ .../_manage-group-member-attributes.mdx | 28 ++++++++++++++ .../project-implementation/index.mdx | 3 ++ .../project-implementation/ios.mdx | 37 +++++++++++++++++++ .../understand/index.mdx | 3 ++ .../understand/ios.mdx | 9 +++++ .../project-implementation/ios.mdx | 22 +++++++++++ .../manage-messages/understand/ios.mdx | 2 + .../project-implementation/ios.mdx | 21 ++++++++++- .../retrieve-messages/understand/ios.mdx | 1 + 10 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 agora-chat/client-api/chat-group/manage-group-member-attributes.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/_manage-group-member-attributes.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/ios.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/ios.mdx diff --git a/agora-chat/client-api/chat-group/manage-group-member-attributes.mdx b/agora-chat/client-api/chat-group/manage-group-member-attributes.mdx new file mode 100644 index 000000000..9ae1c1e36 --- /dev/null +++ b/agora-chat/client-api/chat-group/manage-group-member-attributes.mdx @@ -0,0 +1,13 @@ +--- +title: 'Manage chat group member attributes' +sidebar_position: 5 +type: docs +description: > + Introduces how to use the Agora Chat SDK to manage the attributes of the members of a chat group in your app. +--- + +import ChatGroupMemberAttributes from '@docs/shared/chat-sdk/client-api/chat-group/_manage-group-member-attributes.mdx'; + +export const toc = [{}]; + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/_manage-group-member-attributes.mdx b/shared/chat-sdk/client-api/chat-group/_manage-group-member-attributes.mdx new file mode 100644 index 000000000..a4612f8f5 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/_manage-group-member-attributes.mdx @@ -0,0 +1,28 @@ +import * as data from '@site/data/variables'; +import Understand from '@docs/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx'; +import ProjectImplement from '@docs/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx'; + +Chat groups enable real-time messaging among multiple users. + +This page shows how to use the Agora Chat SDK to manage the attributes of the members of a chat group in your app. + + +## Understand the tech + + + + +## Prerequisites + +Before proceeding, ensure that you meet the following requirements: + +- You have initialized the Chat SDK. For details, . +- You understand the call frequency limits of the Chat APIs supported by different pricing plans as described in [Limitations](/agora-chat/reference/limitations). +- You understand the number of chat groups and chat group members supported by different pricing plans as described in [Pricing Plan Details](/agora-chat/reference/pricing-plan-details). + + +## Implementation + +This section describes how to call the APIs provided by the Chat SDK to implement chat group features. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx new file mode 100644 index 000000000..1ae942c35 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx @@ -0,0 +1,3 @@ +import Ios from './ios.mdx'; + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/ios.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/ios.mdx new file mode 100644 index 000000000..a42a4bb33 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/ios.mdx @@ -0,0 +1,37 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```objc +[AgoraChatClient.sharedClient.groupManager setMemberAttribute:@"groupId" userId:@"userId" attributes:@{@"key":@"value"} completion:^(AgoraChatError * _Nullable error) { + + }]; +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```objc +[AgoraChatClient.sharedClient.groupManager fetchMembersAttributes:@"groupId" userIds:@[@"userId1",@"userId2"] keys:@[@"key1",@"key2"] completion:^(NSDictionary *> * _Nullable attributes, AgoraChatError * _Nullable error) { + +}]; +``` + + +### Listen for attribute changes of a group member + +`AgoraChatGroupManagerDelegate` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `onAttributesChangedOfGroupMember` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```objc +- (void)onAttributesChangedOfGroupMember:(NSString *)groupId userId:(NSString *)userId attributes:(NSDictionary *)attributes operatorId:(NSString *)operatorId { +} +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx new file mode 100644 index 000000000..1ae942c35 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx @@ -0,0 +1,3 @@ +import Ios from './ios.mdx'; + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/ios.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/ios.mdx new file mode 100644 index 000000000..251cb8cc6 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/ios.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `IAgoraChatGroupManager`, `AgoraChatGroupManagerDelegate`, and `AgoraChatGroup` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx index b64033fa0..25c25b994 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx @@ -44,6 +44,28 @@ for (AgoraConversation *conversation in conversations) { ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```objc +[AgoraChatClient.sharedClient.chatManager pinConversation:@"conversationId" isPinned:YES completionBlock:^(AgoraChatError * _Nullable error) { + +}]; +``` + + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```objc +[AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { + +}]; +``` + + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/ios.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/ios.mdx index 4184aed00..0f545ead6 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/ios.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/ios.mdx @@ -6,6 +6,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `deleteConversation`: Deletes a local conversation. - `deleteConversations`: Deletes multiple local conversations. - `AgoraChatConversation.unreadMessagesCount`: Retrieves the count of unread messages in the specified conversation. +- `pinConversation`: Pins a conversation. +- `getPinnedConversationsFromServerWithCursor`: Retrieves the pinned conversations from the server with pagination. - `deleteServerConversation`: Deletes a conversation from the server. - `AgoraChatConversation.loadMessagesStartFromId`: Searches for messages from the local database. - `AgoraChatConversation.insertMessage`: Inserts messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 8a79271db..ed1f92d7e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -16,7 +16,11 @@ For users that do not support `getConversationsFromServerByPage`, call `getConve ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can use these methods to retrieve historical messages from the server: + - By pagination + - For a time range + +#### Retrieve historical messages by pagination You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. @@ -32,6 +36,21 @@ To ensure data reliability, we recommend retrieving less than 50 historical mess }]; ``` +#### Retrieve historical messages for a time range + +Using `AgoraChatFetchServerMessagesOption` to configure the time range parameters, the `fetchMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. + +If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +```objective-c +AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOption alloc] init]; +[AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) { + +}]; +``` + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServerWithTimeStamp` or `removeMessagesFromServerMessageIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx index 32a23d67a..2010c5c29 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx @@ -4,6 +4,7 @@ The Chat SDK uses `IAgoraChatManager` to retrieve historical messages from the s - `getConversationsFromServer`: Retrieves a list of conversations stored on the server. - `asyncFetchHistoryMessagesFromServer`: Retrieves the historical messages in the specified conversation from the server. +- `fetchMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `AgoraChatFetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. - `removeMessagesFromServerWithTimeStamp`/`removeMessagesFromServerMessageIds`: Deletes historical messages from the server unidirectionally. - `deleteServerConversation`: Deletes conversations and their historical messages from the server. From 14d90beec18ebe2da138a828574e921e1a06eb63 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Fri, 3 Nov 2023 12:54:42 +0200 Subject: [PATCH 16/37] rESTful release notes added --- shared/chat-sdk/reference/release-notes/index.mdx | 10 +++++++++- shared/chat-sdk/reference/release-notes/restful.mdx | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 shared/chat-sdk/reference/release-notes/restful.mdx diff --git a/shared/chat-sdk/reference/release-notes/index.mdx b/shared/chat-sdk/reference/release-notes/index.mdx index 6a63c8c2e..60b6e3553 100644 --- a/shared/chat-sdk/reference/release-notes/index.mdx +++ b/shared/chat-sdk/reference/release-notes/index.mdx @@ -5,11 +5,19 @@ import Flutter from './flutter.mdx'; import ReactNative from './react-native.mdx'; import Windows from './windows.mdx'; import Unity from './unity.mdx'; +import RESTful from './restful.mdx'; +- [Client API](#client-api) +- [RESTful API](#restful-api) + +## Client API - \ No newline at end of file + + +## RESTful API + \ No newline at end of file diff --git a/shared/chat-sdk/reference/release-notes/restful.mdx b/shared/chat-sdk/reference/release-notes/restful.mdx new file mode 100644 index 000000000..65eed2d4c --- /dev/null +++ b/shared/chat-sdk/reference/release-notes/restful.mdx @@ -0,0 +1,10 @@ + +## v1.2.0 + +1. Added new REST APIs for management of custom attributes of group members: + +* Setting custom attributes of a group member +* Retrieving all custom attributes of a group member +* Retrieving custom attributes of multiple group members by attribute key + +1. Removed the `nickname` parameter from the RESTful APIs for adding one user or multiple users \ No newline at end of file From 29c4dc6d98a979b25173e5aea66168a1170ec5e5 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 6 Nov 2023 12:59:23 +0200 Subject: [PATCH 17/37] Recall a message addition --- .../send-receive-messages/project-implementation/android.mdx | 2 +- .../send-receive-messages/project-implementation/flutter.mdx | 2 +- .../send-receive-messages/project-implementation/ios.mdx | 2 +- .../project-implementation/react-native.mdx | 2 +- .../send-receive-messages/project-implementation/unity.mdx | 3 ++- .../send-receive-messages/project-implementation/web.mdx | 2 +- .../send-receive-messages/project-implementation/windows.mdx | 2 +- shared/chat-sdk/restful-api/_message-management.mdx | 3 ++- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 3eeb7d055..a40c00001 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -69,7 +69,7 @@ ChatClient.getInstance().chatManager().removeMessageListener(msgListener); After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```java try { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 64d04e39a..ac60610e2 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -257,7 +257,7 @@ String? thumbnailLocalPath = imgBody.thumbnailLocalPath; After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```dart try { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 91a05ac05..4a055711f 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -69,7 +69,7 @@ When a message arrives, the recipient receives an `messagesDidReceive` callback. ### Recall a message After a message is sent, you can recall it. The `recallMessageWithMessageId` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```objective-c [[AgoraChatClient sharedClient].chatManager recallMessageWithMessageId:@"messageId" completion:^(AgoraChatError *aError) { diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index 140b90cdc..b0b1cf6ab 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -188,7 +188,7 @@ ChatClient.getInstance().chatManager.removeAllMessageListener(); After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```typescript ChatClient.getInstance() diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 65117c52a..89d65a26e 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -61,7 +61,8 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). + ```csharp // Call `RecallMessage` to recall the message. SDKClient.Instance.ChatManager.RecallMessage("Message ID", new CallBack( diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index b21037d43..996245b3e 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -121,7 +121,7 @@ WebIM.conn.addEventHandler("eventName",{ After a message is sent, you can recall it. The `recallMessage` method recalls a message saved on the server, whether it is a historical message, offline message or a roaming message. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```javascript /** diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 0f3ece57d..17574c57d 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -61,7 +61,7 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. If you want to adjust the time limit, contact [support@agora.io](mailto:support@agora.io). +You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). ```csharp // Call `RecallMessage` to recall the message. diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index 7da883cba..1e5d81ace 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1443,7 +1443,8 @@ The fields of `bodies` for different message types vary: ## Recall a message Once a message is sent, you can call this API to recall it. This API recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -The default time limit for recalling a message is two minutes. To adjust this limit, contact [support@agora.io](mailto:support@agora.io). + +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). For each App Key, the call frequency limit of this method is 100 per second. From cb5cb9adab568bd748a9727f25d05233bde1742b Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 6 Nov 2023 13:23:17 +0200 Subject: [PATCH 18/37] Review comments --- .../project-implementation/android.mdx | 118 ++++++++------- .../project-implementation/flutter.mdx | 86 +++++------ .../project-implementation/ios.mdx | 65 ++++----- .../project-implementation/react-native.mdx | 107 +++++++------- .../project-implementation/unity.mdx | 126 ++++++++-------- .../project-implementation/web.mdx | 134 +++++++++--------- .../project-implementation/windows.mdx | 126 ++++++++-------- 7 files changed, 390 insertions(+), 372 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index a40c00001..d26311470 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -342,34 +342,36 @@ message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attri Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: +To forward and receive combined messages, refer to the following code: -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. +1. Create a combined message using multiple message IDs: -```java -ChatMessage message = ChatMessage.createCombinedSendMessage(title, summary, compatibleText, msgIds, toChatUsername); -//The chat type: ChatMessage.ChatType.Chat, ChatMessage.GroupChat, and ChatMessage.ChatRoom indicate one-to-one chat, group chat, and room chat respectively. -message.setChatType(ChatMessage.ChatType.Chat); -//Send the message -ChatClient.getInstance().chatManager().sendMessage(message); -``` + ```java + ChatMessage message = ChatMessage.createCombinedSendMessage(title, summary, compatibleText, msgIds, toChatUsername); + // Set the chat type: + // One-to-one chat: ChatMessage.ChatType.Chat + // Group chat: ChatMessage.GroupChat + // Room chat: ChatMessage.ChatRoom + message.setChatType(ChatMessage.ChatType.Chat); + // Send the message + ChatClient.getInstance().chatManager().sendMessage(message); + ``` -```java -ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { - @Override - public void onSuccess(List value) { +2. Download and parse combined messages: - } + ```java + ChatClient.getInstance().chatManager().downloadAndParseCombineMessage(combinedMessage, new ValueCallBack>() { + @Override + public void onSuccess(List value) { - @Override - public void onError(int error, String errorMsg) { + } - } - }); + @Override + public void onError(int error, String errorMsg) { -``` + } + }); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -383,40 +385,46 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```java -String newContent="new content"; -TextMessageBody newTextMessageBody = new TextMessageBody(newContent); -ChatClient.getInstance().chatManager().asyncModifyMessage(targetMessage.getMsgId(), newTextMessageBody, new ValueCallBack() { -@Override -public void onSuccess(ChatMessage value) { - -} - -@Override -public void onError(int error, String errorMsg) { - -} -}); -``` - -```java -// Create a MessageListener object -MessageListener messageListener = new MessageListener() { - //…… - - @Override - public void onMessageContentChanged(ChatMessage messageModified, String operatorId, long operationTime) { - //int operationCount = messageModified.getBody().operationCount(); - // operatorId and operationTime can also be obtained as follows: - // String id = messageModified.getBody().operatorId(); - //long time = messageModified.getBody().operationTime(); - } - }; -//Register the messageListener -ChatClient.getInstance().chatManager().addMessageListener(messageListener); -//Remove the messageListener -ChatClient.getInstance().chatManager().removeMessageListener(messageListener); -``` +To modify a sent message, refer to the following code: + +1. Call `asyncModifyMessage` with the message ID and the new message body: + + ```java + String newContent="new content"; + TextMessageBody newTextMessageBody = new TextMessageBody(newContent); + ChatClient.getInstance().chatManager().asyncModifyMessage(targetMessage.getMsgId(), newTextMessageBody, new ValueCallBack() { + @Override + public void onSuccess(ChatMessage value) { + + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); + ``` + +1. Receive notification of messages modified by other users: + + ```java + // Create a MessageListener object + MessageListener messageListener = new MessageListener() { + //…… + + @Override + public void onMessageContentChanged(ChatMessage messageModified, String operatorId, long operationTime) { + // int operationCount = messageModified.getBody().operationCount(); + // operatorId and operationTime can also be obtained as follows: + // String id = messageModified.getBody().operatorId(); + // long time = messageModified.getBody().operationTime(); + } + }; + // Register the messageListener + ChatClient.getInstance().chatManager().addMessageListener(messageListener); + // Remove the messageListener + ChatClient.getInstance().chatManager().removeMessageListener(messageListener); + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index ac60610e2..119fd68aa 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -280,34 +280,34 @@ ChatClient.getInstance.chatManager.addEventHandler( Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: - -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - -```dart -String title = "Historical messages for one-to-one chats between A and B"; -String summary = - "A: These are historical messages from A. \nB: These are historical messages from B."; -String compatibleText = - "Your current version does not support this type of message. Please upgrade to the latest version."; -final msg = ChatMessage.createCombineSendMessage( - targetId: targetId, - msgIds: msgIds, - title: title, - summary: summary, - compatibleText: compatibleText, -); -await ChatClient.getInstance.chatManager.sendMessage(msg); -``` - -```dart -List list = - await ChatClient.getInstance.chatManager.fetchCombineMessageDetail( - message: combineMessage, -); -``` +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```dart + String title = "Historical messages for one-to-one chats between A and B"; + String summary = + "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = + "Your current version does not support this type of message. Please upgrade to the latest version."; + final msg = ChatMessage.createCombineSendMessage( + targetId: targetId, + msgIds: msgIds, + title: title, + summary: summary, + compatibleText: compatibleText, + ); + await ChatClient.getInstance.chatManager.sendMessage(msg); + ``` + +2. Download and parse combined messages: + + ```dart + List list = + await ChatClient.getInstance.chatManager.fetchCombineMessageDetail( + message: combineMessage, + ); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -321,19 +321,25 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```dart -ChatTextMessageBody body = ChatTextMessageBody(content: "new content"); -await ChatClient.getInstance.chatManager.modifyMessage( - messageId: msgId, - msgBody: body, -); -``` +To modify a sent message, refer to the following code: -```dart -ChatEventHandler( - onMessageContentChanged: (message, operatorId, operationTime) {}, -) -``` +1. Call `modifyMessage` with the message ID and the new message body: + + ```dart + ChatTextMessageBody body = ChatTextMessageBody(content: "new content"); + await ChatClient.getInstance.chatManager.modifyMessage( + messageId: msgId, + msgBody: body, + ); + ``` + +1. Receive notification of messages modified by other users: + + ```dart + ChatEventHandler( + onMessageContentChanged: (message, operatorId, operationTime) {}, + ) + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 4a055711f..4eaca21fc 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -361,32 +361,27 @@ message.chatType = AgoraChatTypeChat; Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: - -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - -```objective-c -AgoraChatCombineMessageBody *body = [[AgoraChatCombineMessageBody alloc] initWithTitle:@"Chat History" summary:@"summary" compatibleText:@"The version is low and unable to display the content." messageIdList:@[@"messageId1",@"messageId2"]]; - AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:@"conversationId" body:body ext:nil]; - [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:^(AgoraChatMessage *aMessage, AgoraChatError *aError) { - -}]; -``` - -```objective-c -- (void)messagesDidReceive:(NSArray *)aMessages -{ - for(AgoraChatMessage* msg in aMessages) { - if (msg.body.type == AgoraChatMessageBodyTypeCombine) { - [AgoraChatClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, AgoraChatError * _Nullable error) { - - }]; +To forward and receive combined messages, refer to the following code: +1. Create a combined message using multiple message IDs: + ```objective-c + AgoraChatCombineMessageBody *body = [[AgoraChatCombineMessageBody alloc] initWithTitle:@"Chat History" summary:@"summary" compatibleText:@"The version is low and unable to display the content." messageIdList:@[@"messageId1",@"messageId2"]]; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:@"conversationId" body:body ext:nil]; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:^(AgoraChatMessage *aMessage, AgoraChatError *aError) { + }]; + ``` +2. Download and parse combined messages: + ```objective-c + - (void)messagesDidReceive:(NSArray *)aMessages + { + for(AgoraChatMessage* msg in aMessages) { + if (msg.body.type == AgoraChatMessageBodyTypeCombine) { + [AgoraChatClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, AgoraChatError * _Nullable error) { + + }]; + } } } -} -``` + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -400,18 +395,20 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```ObjectiveC -AgoraChatTextMessageBody* newBody = [[AgoraChatTextMessageBody alloc] initWithText:@"new content"]; - [AgoraChatClient.sharedClient.chatManager modifyMessage:msgId body:newBody completion:^(AgoraChatError * _Nullable error, AgoraChatMessage * _Nullable message) { - - }]; -``` +To modify a sent message, refer to the following code: +1. Call `modifyMessage` with the message ID and the new message body: + ```objective-c + AgoraChatTextMessageBody* newBody = [[AgoraChatTextMessageBody alloc] initWithText:@"new content"]; + [AgoraChatClient.sharedClient.chatManager modifyMessage:msgId body:newBody completion:^(AgoraChatError * _Nullable error, AgoraChatMessage * _Nullable message) { -```ObjectiveC -- (void)onMessageContentChanged:(AgoraChatMessage *)message operatorId:(NSString *)operatorId operationTime:(NSUInteger)operationTime { + }]; + ``` +1. Receive notification of messages modified by other users: + ```objective-c + - (void)onMessageContentChanged:(AgoraChatMessage *)message operatorId:(NSString *)operatorId operationTime:(NSUInteger)operationTime { -} -``` + } + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index b0b1cf6ab..fa3774e22 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -210,34 +210,31 @@ onMessagesRecalled(messages: ChatMessage[]): void; Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: +To forward and receive combined messages, refer to the following code: +1. Create a combined message using multiple message IDs: + ```typescript + // Construct a combined message. + const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { + title, + summary, + compatibleText, + }); + EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); + ``` +2. Download and parse combined messages: -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - -```typescript -// Construct a combined message. -const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { - title, - summary, - compatibleText, -}); -EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); -``` - -```typescript -// message: The combined message object. -// Asynchronously return the list of original messages. -ChatClient.getInstance() - .chatManager.fetchCombineMessageDetail(message) - .then((messages: ChatMessage[]) => { - console.log("success: ", messages); - }) - .catch((error) => { - console.log("fail: ", error); - }); -``` + ```typescript + // message: The combined message object. + // Asynchronously return the list of original messages. + ChatClient.getInstance() + .chatManager.fetchCombineMessageDetail(message) + .then((messages: ChatMessage[]) => { + console.log("success: ", messages); + }) + .catch((error) => { + console.log("fail: ", error); + }); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -251,33 +248,35 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```typescript -ChatClient.getInstance() - .chatManager.modifyMessageBody(msgId, body) - .then((message) => { - console.log("modify success:", message); - }) - .catch((error) => { - console.warn(error); - }); -``` - -```typescript -ChatClient.getInstance().chatManager.addMessageListener({ - onMessageContentChanged: ( - message: ChatMessage, - lastModifyOperatorId: string, - lastModifyTime: number - ): void => { - console.log( - `${QuickTestScreenChat.TAG}: onMessageContentChanged: `, - JSON.stringify(message), - lastModifyOperatorId, - lastModifyTime - ); - }, -} as ChatMessageEventListener); -``` +To modify a sent message, refer to the following code: +1. Call `modifyMessageBody` with the message ID and the new message body: + ```typescript + ChatClient.getInstance() + .chatManager.modifyMessageBody(msgId, body) + .then((message) => { + console.log("modify success:", message); + }) + .catch((error) => { + console.warn(error); + }); + ``` +1. Receive notification of messages modified by other users: + ```typescript + ChatClient.getInstance().chatManager.addMessageListener({ + onMessageContentChanged: ( + message: ChatMessage, + lastModifyOperatorId: string, + lastModifyTime: number + ): void => { + console.log( + `${QuickTestScreenChat.TAG}: onMessageContentChanged: `, + JSON.stringify(message), + lastModifyOperatorId, + lastModifyTime + ); + }, + } as ChatMessageEventListener); + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 89d65a26e..071bd5d19 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -404,39 +404,38 @@ if (found) { Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: - -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - - -```csharp -String title = "Historical messages for one-to-one chats between A and B"; -String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; -String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; -Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); - -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - // Handling logic upon the success of sending the message - }, - onError: (code, desc) => { - // Handling logic upon a failure in sending the message - } -)) ; -``` - -```csharp -SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) = > { - // Add the handling logic and show the message list - } , - onError: (code, desc) = > { - // Handle an error - } - ) ) ; -``` +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```csharp + String title = "Historical messages for one-to-one chats between A and B"; + String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; + Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); + + SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + // Handling logic upon sending success + }, + onError: (code, desc) => { + // Handling logic if sendMessage fails + } + )); + ``` + +2. Download and parse combined messages: + + ```csharp + SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // Add the handling logic and show the message list + }, + onError: (code, desc) => { + // Handle an error + } + )); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -450,38 +449,45 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```csharp - TextBody tb = new TextBody("new content"); - SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( - onSuccess: (dmsg) = > - { - } , - onError: (code, desc) = > - { - } - )) ; -``` +To modify a sent message, refer to the following code: -```csharp -// Inherit and implement `IChatManagerDelegate`. -public class ChatManagerDelegate : IChatManagerDelegate { - public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) - { - // You can obtain operatorId and operationTime in the following way: - // string id = msg.Body.OperatorId; - // long time = msg.Body.OperationTime; - } - } +1. Call `ModifyMessage` with the message ID and the new message body: -// Add a delegate. + ```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) => + { -ChatManagerDelegate adelegate = new ChatManagerDelegate(); + }, + onError: (code, desc) => + { -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + } + )); + ``` -// Remove the delegate when it is unnecessary. -SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); -``` +1. Receive notification of messages modified by other users: + + ```csharp + // Inherit and implement `IChatManagerDelegate`. + public class ChatManagerDelegate : IChatManagerDelegate { + + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime as follows: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + + // Add a delegate. + ChatManagerDelegate adelegate = new ChatManagerDelegate(); + SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + + // Remove the delegate when it is no longer required + SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 996245b3e..7b1265558 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -506,55 +506,49 @@ function sendPrivateText() { Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: - -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - - -```javaScript -let option = { - chatType: "singleChat", - type: "combine", - to: "userId", - compatibleText: "Your SDK does not support combined messages. Please upgrade.", - title: "Chat history", - summary: "hi", - messageList: [ - // message body - { - type: "txt", - chatType: "singleChat", - // ... +To forward and receive combined messages, refer to the following code: +1. Create a combined message using multiple message IDs: + ```javascript + let option = { + chatType: "singleChat", + type: "combine", + to: "userId", + compatibleText: "Your SDK does not support combined messages. Please upgrade.", + title: "Chat history", + summary: "hi", + messageList: [ + // message body + { + type: "txt", + chatType: "singleChat", + // ... + }, + ], + onFileUploadComplete: (data) => { + option.url = data.url; }, - ], - onFileUploadComplete: (data) => { - option.url = data.url; - }, -}; -let msg = AC.message.create(option); -connection.send - .send(msg) - .then((res) => { - console.log("Succeeded in sending the message", res); - }) - .catch((err) => { - console.log("Failed to send the message", err); - }); - -``` + }; + let msg = AC.message.create(option); + connection.send + .send(msg) + .then((res) => { + console.log("Succeeded in sending the message", res); + }) + .catch((err) => { + console.log("Failed to send the message", err); + }); -```javaScript -connection - .downloadAndParseCombineMessage({ - url: msg.url, - secret: msg.secret, - }) - .then((res) => { - console.log("The list of original messages obtained after parsing", res); - }); -``` + ``` +2. Download and parse combined messages: + ```javascript + connection.downloadAndParseCombineMessage({ + url: msg.url, + secret: msg.secret, + }) + .then((res) => { + console.log("The list of original messages obtained after parsing", res); + }); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -568,30 +562,32 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```javaScript -// Adds the message modification event -connection.addEventHandler("modifiedMessage", { - onModifiedMessage: message => { - console.log('onModifiedMessage', message) - }, -}); - -const textMessage = AC.message.create({ - type: 'txt', - msg: 'message content', - to: 'username', - chatType: 'singleChat', -}); - -connection.modifyMessage({ messageId: 'messageId', modifiedMessage: textMessage }) - .then((res) => { - console.log(res.message) - }) - .catch((e) => { - console.log(e) +1. Call `modifyMessage` with the message ID and the new message body: + ```javascript + const textMessage = AC.message.create({ + type: 'txt', + msg: 'message content', + to: 'username', + chatType: 'singleChat', }); -``` + connection.modifyMessage({ messageId: 'messageId', modifiedMessage: textMessage }) + .then((res) => { + console.log(res.message) + }) + .catch((e) => { + console.log(e) + }); + ``` +1. Receive notification of messages modified by other users: + ```javascript + // Adds the message modification event + connection.addEventHandler("modifiedMessage", { + onModifiedMessage: message => { + console.log('onModifiedMessage', message) + }, + }); + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 17574c57d..be9e5a840 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -404,39 +404,38 @@ if (found) { Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. -The process of sending and receiving a consolidated message is as follows: - -1. The sender creates a consolidated message with a list of original messages. -1. The sender sends the consolidated message. -1. Upon receiving the consolidated message, the recipient parses it to get the list of original messages. - -```csharp -String title = "Historical messages for one-to-one chats between A and B"; -String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; -String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; -Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - o nSuccess: () = > { - // Handling logic upon the success of sending the message - } , - onError: (code, desc) = > { - // Handling logic upon a failure in sending the message - } - ) ) ; -``` - - -```csharp - -SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) = > { - // Add the handling logic and show the message list - } , - onError: (code, desc) = > { - // Handle an error - } -)) ; -``` +To forward and receive combined messages, refer to the following code: + +1. Create a combined message using multiple message IDs: + + ```csharp + String title = "Historical messages for one-to-one chats between A and B"; + String summary = "A: These are historical messages from A. \nB: These are historical messages from B."; + String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version."; + Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList); + + SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + // Handling logic upon sending success + }, + onError: (code, desc) => { + // Handling logic if sendMessage fails + } + )); + ``` + +2. Download and parse combined messages: + + ```csharp + SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // Add the handling logic and show the message list + }, + onError: (code, desc) => { + // Handle an error + } + )); + ``` For further details see [Multiple messages forwarding limitations](../../reference/limitations#multiple-messages-forwarding-limitations). @@ -450,38 +449,45 @@ Every end user or chat group member may edit messages that they have sent. In th For the edited message, except the message body, other information included in the message like the message sender, recipient, and message extension attributes remain unchanged. -```csharp - TextBody tb = new TextBody("new content"); - SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( - onSuccess: (dmsg) = > - { - } , - onError: (code, desc) = > - { - } - ) ) ; -``` +To modify a sent message, refer to the following code: -```csharp +1. Call `ModifyMessage` with the message ID and the new message body: -// Inherit and implement `IChatManagerDelegate`. - public class ChatManagerDelegate : IChatManagerDelegate { - public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) - { - // You can obtain operatorId and operationTime in the following way: - // string id = msg.Body.OperatorId; - // long time = msg.Body.OperationTime; - } - } + ```csharp + TextBody tb = new TextBody("new content"); + SDKClient.Instance.ChatManager.ModifyMessage(msgId, tb, new ValueCallBack( + onSuccess: (dmsg) => + { -// Add a delegate. -ChatManagerDelegate adelegate = new ChatManagerDelegate(); -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + }, + onError: (code, desc) => + { -// Remove the delegate when it is unnecessary. -SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); -``` + } + )); + ``` + +1. Receive notification of messages modified by other users: + + ```csharp + // Inherit and implement `IChatManagerDelegate`. + public class ChatManagerDelegate : IChatManagerDelegate { + + public void OnMessageContentChanged(Message msg, string operatorId, long operationTime) + { + // You can obtain operatorId and operationTime as follows: + // string id = msg.Body.OperatorId; + // long time = msg.Body.OperationTime; + } + } + + // Add a delegate. + ChatManagerDelegate adelegate = new ChatManagerDelegate(); + SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + // Remove the delegate when it is no longer required. + SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); + ``` For further details see [Sent message modification limitations](../../reference/limitations#sent-message-modification-limitations). From 2b2f73bd6d000991babb521df08c0307e4b638d0 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Tue, 7 Nov 2023 14:21:15 +0200 Subject: [PATCH 19/37] Retrieve messages update --- .../project-implementation/android.mdx | 12 ++++++++---- .../project-implementation/flutter.mdx | 10 ++++++++-- .../retrieve-messages/project-implementation/ios.mdx | 12 ++++++++---- .../project-implementation/react-native.mdx | 10 ++++++++-- .../project-implementation/unity.mdx | 10 ++++++++-- .../retrieve-messages/project-implementation/web.mdx | 12 ++++++++---- .../project-implementation/windows.mdx | 10 ++++++++-- 7 files changed, 56 insertions(+), 20 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 104b3ac13..8f621f222 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -49,13 +49,17 @@ If you still use the `asyncFetchConversationsFromServer` method to retrieve the ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. - -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index a617dfeb3..6d0a54d45 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -29,11 +29,17 @@ For users that do not support `fetchConversationListFromServer`, call `getConver ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 8a79271db..a0a43369b 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -16,13 +16,17 @@ For users that do not support `getConversationsFromServerByPage`, call `getConve ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. - -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 58124b793..bb010655c 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -22,11 +22,17 @@ For users that do not support `fetchConversationsFromServerWithPage`, call `fetc ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index da0757d0b..4f67a83bf 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -29,11 +29,17 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 403b5f483..6b6984d31 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -16,13 +16,17 @@ If you still use the `getConversationlist` method to retrieve the conversations ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. - -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 2294ded5e..3688862e0 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -30,11 +30,17 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -The Agora Chat server stores messages for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: + +- 1:1 private chat: Send 500 offline messages/conversation by default; +- Chat Group: Send 200 offline messages/conversation by default; +- Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. + +For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. From 23f5aef9ed394b492301cb84fb0592dbe8d10431 Mon Sep 17 00:00:00 2001 From: Dasun Nirmitha Date: Thu, 9 Nov 2023 15:00:21 +0530 Subject: [PATCH 20/37] 706 changes for all platforms. --- .../project-implementation/android.mdx | 78 +++++++++++++++++++ .../project-implementation/flutter.mdx | 52 +++++++++++++ .../project-implementation/index.mdx | 14 +++- .../project-implementation/react-native.mdx | 62 +++++++++++++++ .../project-implementation/unity.mdx | 75 ++++++++++++++++++ .../project-implementation/web.mdx | 54 +++++++++++++ .../project-implementation/windows.mdx | 74 ++++++++++++++++++ .../understand/android.mdx | 9 +++ .../understand/flutter.mdx | 9 +++ .../understand/index.mdx | 14 +++- .../understand/react-native.mdx | 9 +++ .../understand/unity.mdx | 9 +++ .../understand/web.mdx | 9 +++ .../understand/windows.mdx | 9 +++ .../project-implementation/android.mdx | 50 ++++++++++++ .../project-implementation/flutter.mdx | 26 +++++++ .../project-implementation/index.mdx | 2 + .../project-implementation/react-native.mdx | 32 ++++++++ .../project-implementation/unity.mdx | 44 +++++++++++ .../project-implementation/web.mdx | 19 +++++ .../project-implementation/windows.mdx | 43 ++++++++++ .../manage-messages/understand/android.mdx | 2 + .../manage-messages/understand/flutter.mdx | 2 + .../manage-messages/understand/index.mdx | 2 + .../understand/react-native.mdx | 2 + .../manage-messages/understand/unity.mdx | 2 + .../manage-messages/understand/web.mdx | 10 +++ .../manage-messages/understand/windows.mdx | 2 + .../project-implementation/android.mdx | 53 ++++++++++++- .../project-implementation/flutter.mdx | 35 ++++++++- .../project-implementation/unity.mdx | 37 ++++++++- .../project-implementation/web.mdx | 13 ++-- .../project-implementation/windows.mdx | 37 ++++++++- .../retrieve-messages/understand/android.mdx | 1 + .../retrieve-messages/understand/flutter.mdx | 1 + .../retrieve-messages/understand/unity.mdx | 1 + .../retrieve-messages/understand/web.mdx | 2 +- .../retrieve-messages/understand/windows.mdx | 1 + 38 files changed, 884 insertions(+), 12 deletions(-) create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/android.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/flutter.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/react-native.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/unity.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/web.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/windows.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/android.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/flutter.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/react-native.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/unity.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/web.mdx create mode 100644 shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/windows.mdx create mode 100644 shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx create mode 100644 shared/chat-sdk/client-api/messages/manage-messages/understand/web.mdx diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/android.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/android.mdx new file mode 100644 index 000000000..695c1835b --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/android.mdx @@ -0,0 +1,78 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```java +Map attributeMap = new HashMap<>(); +attributeMap.put("nickName",nickName); + +ChatClient.getInstance().groupManager().asyncSetGroupMemberAttributes(groupId, userId, attributeMap, new CallBack() { + @Override + public void onSuccess() { + } + @Override + public void onError(int code, String error) { + } +}); +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```java +List keyList = new ArrayList<>(); +keyList.add("nickName"); + +List userIds = new ArrayList<>(); +userIds.add("Tom"); +userIds.add("Jack"); + +ChatClient.getInstance().groupManager().asyncFetchGroupMembersAttributes(groupId, userIds, keyList, new ValueCallBack>>() { + @Override + public void onSuccess(Map> value) { + if (value != null){ + for (String user : userIds) { + Map map = value.get(user); + if (map != null){ + //…… + } + } + } + } + + @Override + public void onError(int code, String error) { + } +}); +``` + +### Listen for attribute changes of a group member + +`GroupChangeListener` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `onGroupMemberAttributeChanged` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```java +//Create a GroupChangeListener object +GroupChangeListener groupChangeListener = new GroupChangeListener() { + @Override + public void onGroupMemberAttributeChanged(String groupId, String userId, Map attribute, String from) { + if ( attribute != null && attribute.size() > 0){ + //EMLog.d(TAG,"onGroupMemberAttributeChanged: " + groupId +" - "+ attribute.toString()); + } + } +}; + +//Add a group change listener: +ChatClient.getInstance().groupManager().addGroupChangeListener(groupChangeListener); + +//Remove a group change listener: +ChatClient.getInstance().groupManager().removeGroupChangeListener(groupChangeListener); +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/flutter.mdx new file mode 100644 index 000000000..314b94eff --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/flutter.mdx @@ -0,0 +1,52 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```dart +await ChatClient.getInstance.groupManager.setMemberAttributes( + groupId: groupId, + userId: userId, + attributes: {'key': 'value'}, +); +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```dart +Map attribute = + await ChatClient.getInstance.groupManager.fetchMemberAttributes( + groupId: 'groupId', + userId: 'userId', +); +``` + + +### Listen for attribute changes of a group member + +`ChatGroupEventHandler` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `onAttributesChangedOfGroupMember` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```dart +// Add an event handler +ChatClient.getInstance.groupManager.addEventHandler( + 'UNIQUE_HANDLER_ID', + ChatGroupEventHandler( + onAttributesChangedOfGroupMember: + (groupId, userId, attributes, operatorId) {}, + ), +); + + +... +// Remove an event handler +ChatClient.getInstance.groupManager.removeEventHandler('UNIQUE_HANDLER_ID'); +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx index 1ae942c35..218e793f3 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/index.mdx @@ -1,3 +1,15 @@ +import Android from './android.mdx'; import Ios from './ios.mdx'; +import Flutter from './flutter.mdx'; +import ReactNative from './react-native.mdx'; +import Windows from './windows.mdx'; +import Web from './web.mdx'; +import Unity from './unity.mdx'; - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/react-native.mdx new file mode 100644 index 000000000..aa8cbbdec --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/react-native.mdx @@ -0,0 +1,62 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```typescript +// groupId: The group ID. +// member: The user ID of the group member. +// attributes: The custom attributes to set. +ChatClient.getInstance() + .groupManager.setMemberAttribute(groupId, member, attributes) + .then(() => { + console.log("set group members attributes success."); + }) + .catch((reason) => { + console.log("set group members attributes fail.", reason); + }); + +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```typescript +// groupId: The group ID. +// member: The user ID of the group member. +ChatClient.getInstance() + .groupManager.fetchMemberAttributes(groupId, member) + .then((attributes: Record | undefined) => { + console.log("get group members attributes success.", attributes); + }) + .catch((reason) => { + console.log("get group members attributes fail.", reason); + }); +``` + + +### Listen for attribute changes of a group member + +`ChatGroupEventListener` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `onMemberAttributesChanged` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```typescript + onMemberAttributesChanged(params: { + groupId: string; + member: string; + attributes: any; + operator: string; + }): void { + console.log(`${QuickTestScreenBase.TAG}: onStateChanged:`, params); + this.that.setState({ + recvResult: `onMemberAttributesChanged: ` + params, + }); + } +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/unity.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/unity.mdx new file mode 100644 index 000000000..20c2362ba --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/unity.mdx @@ -0,0 +1,75 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```csharp +Dictionary dict = new Dictionary(); +dict.Add("key", "value"); + +SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( + onSuccess: () => + { + Console.WriteLine($"SetMemberAttributes success."); + }, + onError: (code, desc) => + { + Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); + } +)); + +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```csharp +List userList = new List(); +userList.Add("user"); + +// keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. +List keyList = new List(); +keyList.Add("key"); + +SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( + onSuccess: (dict) => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + + +### Listen for attribute changes of a group member + +`IGroupManagerDelegate` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `OnUpdateMemberAttributesFromGroup` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```csharp + +// Inherit and implement `IGroupManagerDelegate`. +public class GroupManagerDelegate : IGroupManagerDelegate { + + public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) + { + } +} + +// Add a delegate. +GroupManagerDelegate adelegate = new GroupManagerDelegate(); +SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); + +// Remove the delegate when it is unnecessary. +SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/web.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/web.mdx new file mode 100644 index 000000000..0dc63a3eb --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/web.mdx @@ -0,0 +1,54 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```javaScript +let options = { + groupId: 'groupId', + userId: 'userId', + memberAttributes: { + key: 'value' + }, +} + +connection.setGroupMemberAttributes(options).then((res) => { + console.log(res) +}).catch((e) => { + console.log(e) +}) +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```javaScript +let options = { + groupId: 'groupId', + userId: 'userId' +} + +connection.getGroupMemberAttributes(options).then((res) => { + console.log(res) +}).catch((e) => { + console.log(e) +}) +``` + + +### Listen for attribute changes of a group member + +`GroupEvent` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, a `memberAttributesUpdate` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```javaScript +case "memberAttributesUpdate": + break; +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/windows.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/windows.mdx new file mode 100644 index 000000000..2ff74684f --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/project-implementation/windows.mdx @@ -0,0 +1,74 @@ + + +### Set custom attributes of a group member via key and value items + +Each chat group member can set their own attributes. Chat group admins/owners can also modify all members' attributes. Each custom attribute should be in key-value format. + +Refer to the following sample code to set a custom attribute of a group member: + +```csharp +Dictionary dict = new Dictionary(); +dict.Add("key", "value"); + +SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( + onSuccess: () => + { + Console.WriteLine($"SetMemberAttributes success."); + }, + onError: (code, desc) => + { + Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); + } +)); + +``` + +### Fetch group member custom attributes + +Chat group members and group admins/owners can retrieve custom attributes of multiple group members by attribute key. + +Refer to the following sample code to use the attribute key to fetch custom attributes of multiple group members: + +```csharp +List userList = new List(); +userList.Add("user"); + +// keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. +List keyList = new List(); +keyList.Add("key"); + +SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( + onSuccess: (dict) => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + + +### Listen for attribute changes of a group member + +`IGroupManagerDelegate` class holds callbacks that can be used to monitor the change of any key-value items. When such a change occurs, an `OnUpdateMemberAttributesFromGroup` callback will notify the Client SDK by returning chat group ID, UID, and key-value pairs of the changes. + +```csharp +// Inherit and implement `IGroupManagerDelegate`. +public class GroupManagerDelegate : IGroupManagerDelegate { + public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) + { + + } +} + +// Add a delegate. +GroupManagerDelegate adelegate = new GroupManagerDelegate(); +SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); + +// Remove the delegate when it is unnecessary. +SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/android.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/android.mdx new file mode 100644 index 000000000..37f08e642 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/android.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `Group`, `GroupManager`, and `GroupChangeListener` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/flutter.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/flutter.mdx new file mode 100644 index 000000000..d199a2096 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/flutter.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `ChatGroup`, `ChatGroupManager`, and `ChatGroupEventHandler` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx index 1ae942c35..218e793f3 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/index.mdx @@ -1,3 +1,15 @@ +import Android from './android.mdx'; import Ios from './ios.mdx'; +import Flutter from './flutter.mdx'; +import ReactNative from './react-native.mdx'; +import Windows from './windows.mdx'; +import Web from './web.mdx'; +import Unity from './unity.mdx'; - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/react-native.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/react-native.mdx new file mode 100644 index 000000000..91adffa45 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/react-native.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `ChatGroup`, `ChatGroupManager`, and `ChatGroupEventListener` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/unity.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/unity.mdx new file mode 100644 index 000000000..58e5a51cf --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/unity.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `Group`, `IGroupManager`, and `IGroupManagerDelegate` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/web.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/web.mdx new file mode 100644 index 000000000..2f5641049 --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/web.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `GroupManager` and `Group` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/windows.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/windows.mdx new file mode 100644 index 000000000..3e18ba04f --- /dev/null +++ b/shared/chat-sdk/client-api/chat-group/manage-group-member-attributes/understand/windows.mdx @@ -0,0 +1,9 @@ + + +The Chat SDK provides the `Group`, `IGroupManager`, and `IGroupManagerDelegate` classes for chat group management, which allows you to implement the following features: + +- Set custom attributes of a group member via key and value items. +- Fetch group member custom attributes. +- Listen for attribute changes of a group member. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx index e04ea9800..844154e7f 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx @@ -37,6 +37,56 @@ Refer to the following code example to retrieve the count of all unread messages ChatClient.getInstance().chatManager().getUnreadMessageCount(); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```java +ChatClient.getInstance().chatManager().asyncPinConversation(conversationId, true, new CallBack() { + @Override + public void onSuccess() { + } + + @Override + public void onError(int code, String error) { + } +}); +``` + + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```java +String cursor = ""; +int limit = 40; +List conversations = new ArrayList<>(); +doAsyncFetchPinnedConversationsFromServer(limit,cursor,conversations); + +private void doAsyncFetchPinnedConversationsFromServer(final int limit, final String cursor,List conversations){ + ChatClient.getInstance().chatManager().asyncFetchPinnedConversationsFromServer(limit, cursor, new ValueCallBack>() { + @Override + public void onSuccess(CursorResult value) { + if (value != null) { + List list = value.getData(); + if (list != null && list.size() > 0) { + conversations.addAll(list); + } + String newCursor = value.getCursor(); + if( !TextUtils.isEmpty(newCursor)) { + doAsyncFetchPinnedConversationsFromServer(limit, newCursor, conversations); + } + } + } + + @Override + public void onError(int error, String errorMsg) { + } + }); +} +``` + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx index dd2013d78..f0f24450e 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx @@ -55,6 +55,32 @@ int unreadCount = await ChatClient.getInstance.chatManager.getUnreadMessageCount(); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```dart +ChatClient.getInstance.chatManager.pinConversation( + conversationId: conversationId, + isPinned: isPinned, +); +``` + + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```dart +String? cursor; +int pageSize = 10; +ChatCursorResult result = + await ChatClient.getInstance.chatManager.fetchPinnedConversations( + cursor: cursor, + pageSize: pageSize, +); +``` + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx index a0f59ac2a..6c3a2630d 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx @@ -1,5 +1,6 @@ import Android from './android.mdx'; import Ios from './ios.mdx'; +import Web from './web.mdx'; import Flutter from './flutter.mdx'; import ReactNative from './react-native.mdx'; import Windows from './windows.mdx'; @@ -7,6 +8,7 @@ import Unity from './unity.mdx'; + diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx index 61c58d76d..d7958d3ed 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx @@ -73,6 +73,38 @@ ChatClient.getInstance() }); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```typescript +// isPinned: Sets whether to pin a conversation. +ChatClient.getInstance() + .chatManager.pinConversation(convId, isPinned) + .then(() => { + console.log("pin conversions success"); + }) + .catch((reason) => { + console.log("pin conversions fail.", reason); + }); +``` + + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```typescript +ChatClient.getInstance() + .chatManager.fetchPinnedConversationsFromServerWithCursor(cursor, pageSize) + .then(() => { + console.log("get conversions success"); + }) + .catch((reason) => { + console.log("get conversions fail.", reason); + }); +``` + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx index ad480c6c7..e0c6fa109 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx @@ -45,6 +45,50 @@ Refer to the following code example to retrieve the count of all unread messages SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```csharp +SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( + onSuccess: () => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```csharp +int limit = 10; +string cursor = ""; +bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next query + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); +``` + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx new file mode 100644 index 000000000..b6c260343 --- /dev/null +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx @@ -0,0 +1,19 @@ + + +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```javaScript +connection.pinConversation({conversationId:'conversationId', conversationType: 'singleChat', isPinned: true}) +``` + +### Retrieve the pinned conversations from the server with pagination + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```javaScript +connection.getServerPinnedConversations({pageSize:50, cursor: ''}) +``` + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx index c8b860bd8..8233bc3aa 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx @@ -45,6 +45,49 @@ Refer to the following code example to retrieve the count of all unread messages SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```csharp +SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( + onSuccess: () => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + +### Retrieve the pinned conversations from the server + +Refer to the following code example to get a list of pinned conversations from the server: + +```csharp +int limit = 10; +string cursor = ""; +bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next query + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); +``` + ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx index be67fa2ad..acc368082 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx @@ -7,6 +7,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `deleteConversationFromServer`: Delete a conversation from the server. - `Conversation.getUnreadMsgCount`: Retrieves the count of unread messages in the specified conversation. - `getUnreadMessageCount`: Retrieves the count of all unread messages. +- `asyncPinConversation`: Pins a conversation. +- `asyncFetchPinnedConversationsFromServer`: Retrieves the pinned conversations from the server with pagination. - `searchMsgFromDB`: Searches for messages from the local database. - `Conversation.insertMessage`: Inserts messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/flutter.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/flutter.mdx index 22d52c85a..64f6d09eb 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/flutter.mdx @@ -6,6 +6,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `ChatManage.deleteConversation`: Deletes the specified conversation. - `ChatConversation.getUnreadMessageCount`: Retrieves the count of unread messages in the specified conversation. - `ChatManager.getUnreadMessageCount`: Retrieves the count of all unread messages. +- `ChatManager.pinConversation`: Pins a conversation. +- `ChatManager.fetchPinnedConversations`: Retrieves the pinned conversations from the server with pagination. - `ChatManager.deleteRemoteConversation`: Deletes the conversation and historical messages from the server. - `ChatManager.searchMsgFromDB`: Searches for messages from the local database. - `ChatConversation.insertMessage`: Inserts messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/index.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/index.mdx index a0f59ac2a..6c3a2630d 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/index.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/index.mdx @@ -1,5 +1,6 @@ import Android from './android.mdx'; import Ios from './ios.mdx'; +import Web from './web.mdx'; import Flutter from './flutter.mdx'; import ReactNative from './react-native.mdx'; import Windows from './windows.mdx'; @@ -7,6 +8,7 @@ import Unity from './unity.mdx'; + diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/react-native.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/react-native.mdx index a649e823e..90ced4664 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/react-native.mdx @@ -6,6 +6,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `ChatManage.deleteConversation`: Deletes the specified conversation. - `ChatConversation.getConversationUnreadCount`: Retrieves the count of unread messages in the specified conversation. - `ChatManager.getUnreadCount`: Retrieves the count of all unread messages. +- `ChatManager.pinConversation`: Pins a conversation. +- `ChatManager.getPinnedConversationsFromServerWithCursor`: Retrieves the pinned conversations from the server with pagination. - `ChatManager.removeConversationFromServer`: Deletes the conversation and historical messages from the server. - `ChatManager.searchMsgFromDB`: Searches for messages from the local database. diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/unity.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/unity.mdx index bafb83e4b..0ef37d9a7 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/unity.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/unity.mdx @@ -6,6 +6,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `IChatManage.DeleteConversation`: Deletes the specified conversation. - `IConversationManager.UnReadCount`: Retrieves the count of unread messages in the specified conversation. - `IChatManager.GetUnreadMessageCount`: Retrieves the count of all unread messages. +- `IChatManager.PinConversation`: Pins a conversation. +- `IChatManager.GetConversationsFromServerWithCursor`: Retrieves the pinned conversations from the server with pagination. - `IChatManager.DeleteConversationFromServer`: Deletes the conversation from the server. - `IChatManager.searchMsgFromDB`: Searches for messages from the local database. - `Conversation.insertMessage`: Inserts messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/web.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/web.mdx new file mode 100644 index 000000000..27afb3375 --- /dev/null +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/web.mdx @@ -0,0 +1,10 @@ + + +SQLCipher is used to encrypt the database that stores local messages. The Chat SDK uses `ChatManager` to manage local messages. Followings are the core methods: + +- `getServerConversations`: Loads the conversation list from the server with pagination. +- `deleteConversation`: Deletes the conversation. +- `pinConversation`: Pins a conversation. +- `getServerPinnedConversations`: Retrieves the list of pinned conversations from the server with pagination. + + \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/windows.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/windows.mdx index fbd047a0a..4b1cb38f1 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/windows.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/windows.mdx @@ -6,6 +6,8 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat S - `IChatManage.DeleteConversation`: Deletes the specified conversation. - `IConversationManager.UnReadCount`: Retrieves the count of unread messages in the specified conversation. - `IChatManager.GetUnreadMessageCount`: Retrieves the count of all unread messages. +- `IChatManager.PinConversation`: Pins a conversation. +- `IChatManager.GetConversationsFromServerWithCursor`: Retrieves conversations from the server. - `IChatManager.DeleteConversationFromServer`: Deletes the conversation from the server. - `IChatManager.searchMsgFromDB`: Searches for messages from the local database. - `Conversation.insertMessage`: Inserts messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 104b3ac13..8877dc561 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -49,7 +49,11 @@ If you still use the `asyncFetchConversationsFromServer` method to retrieve the ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can use these methods to retrieve historical messages from the server: + - By pagination + - For a time range + +#### Retrieve historical messages by pagination You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. @@ -71,6 +75,53 @@ ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(conversationId, }); ``` +#### Retrieve historical messages for a time range + +Using `FetchMessageOption` to configure the time range parameters, the `asyncFetchHistoryMessages` method can retrieve historical messages of a conversation from the server for a specific range of time. + +If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +```java +String conversationId=" "; +Conversation.ConversationType type=Conversation.ConversationType.Chat; +FetchMessageOption option=new FetchMessageOption(); +//for example +//option.setIsSave(true); +int pageSize = 40; +String cursor = ""; +List messages = new ArrayList<>(); +doAsyncFetchHistoryMessages(conversationId,type,pageSize,cursor,option,messages); + +private void doAsyncFetchHistoryMessages(String conversationId, + Conversation.ConversationType type, + int pageSize,String cursor, + FetchMessageOption option, + List messages){ + ChatClient.getInstance().chatManager().asyncFetchHistoryMessages(conversationId, type, pageSize, cursor, option, new ValueCallBack>() { + @Override + public void onSuccess(CursorResult value) { + if (value != null ) { + List list = value.getData(); + if (list != null && list.size() > 0) { + messages.addAll(list); + } + String newCursor = value.getCursor(); + if( !TextUtils.isEmpty(newCursor)) { + doAsyncFetchHistoryMessages(conversationId, type, pageSize, newCursor, option, messages); + } + } + } + + @Override + public void onError(int error, String errorMsg) { + + } + }); +} +``` + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index a617dfeb3..5ca35d3b0 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -29,7 +29,11 @@ For users that do not support `fetchConversationListFromServer`, call `getConver ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can use these methods to retrieve historical messages from the server: + - By pagination + - For a time range + +#### Retrieve historical messages by pagination If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -58,6 +62,35 @@ try { } ``` +#### Retrieve historical messages for a time range + +Using `FetchMessageOptions` to configure the time range parameters, the `fetchHistoryMessagesByOption` method can retrieve historical messages of a conversation from the server for a specific range of time. + +If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +```dart +ChatConversationType conversationType = ChatConversationType.Chat; +FetchMessageOptions options = FetchMessageOptions( + from: senderId, + direction: ChatSearchDirection.Up, + startTs: 1695720454000, + endTs: 1695720554000, + needSave: false, +); + +ChatCursorResult result = + await ChatClient.getInstance.chatManager.fetchHistoryMessagesByOption( + conversationId, + conversationType, + options: options, + cursor: cursor, + pageSize: pageSize, +); + +``` + ### Delete historical messages from the server unidirectionally Call `deleteRemoteMessagesBefore` or `deleteRemoteMessagesWithIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index da0757d0b..6e5650891 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -29,7 +29,11 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can use these methods to retrieve historical messages from the server: + - By pagination + - For a time range + +#### Retrieve historical messages by pagination If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -49,6 +53,37 @@ SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, ty )); ``` +#### Retrieve historical messages for a time range + +Using `FetchServerMessagesOption` to configure the time range parameters, the `FetchHistoryMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. + +If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +```csharp +FetchServerMessagesOption option = new FetchServerMessagesOption(); +option.IsSave = false; +option.Direction = MessageSearchDirection.UP; +option.From = "user"; +option.MsgTypes = new List(); +option.MsgTypes.Add(MessageBodyType.TXT); +option.MsgTypes.Add(MessageBodyType.VIDEO); +option.StartTime = 1695720454000; +option.EndTime = 1695720554000; + +SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( + onSuccess: (result) => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + ### Delete historical messages from the server unidirectionally Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 403b5f483..fb0d820d8 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -2,14 +2,17 @@ ## Retrieve a list of conversations from the server -Call `getConversationlist` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. +Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user.
    Do not use mixed upper-case.
    -```java -// pageNum: The current page number, starting from 1. -// pageSize: The number of conversations to get per page. The value range is [1,20]. -connection.getConversationlist({pageNum: 1, pageSize: 20}).then((res) => {}) +```javaScript +// pageSize: The number of conversations that you expect to get on each page. The value range is [1,50] and the default value is `20`. +// cursor: The cursor position for starting to get data. If you pass in an empty string (''), the SDK retrieves conversations from the latest active one. +connection.getServerConversations({pageSize:50, cursor: ''}).then((res)=>{ + console.log(res) +}) + ``` If you still use the `getConversationlist` method to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 2294ded5e..321c1286e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -30,7 +30,11 @@ For users that do not support `GetConversationsFromServerWithPage`, call `GetCon ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. +After retrieving conversations, you can use these methods to retrieve historical messages from the server: + - By pagination + - For a time range + +#### Retrieve historical messages by pagination If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -50,6 +54,37 @@ SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, ty )); ``` +#### Retrieve historical messages for a time range + +Using `FetchServerMessagesOption` to configure the time range parameters, the `FetchHistoryMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. + +If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. + +The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. + +```csharp +FetchServerMessagesOption option = new FetchServerMessagesOption(); +option.IsSave = false; +option.Direction = MessageSearchDirection.UP; +option.From = "user"; +option.MsgTypes = new List(); +option.MsgTypes.Add(MessageBodyType.TXT); +option.MsgTypes.Add(MessageBodyType.VIDEO); +option.StartTime = 1695720454000; +option.EndTime = 1695720554000; + +SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( + onSuccess: (result) => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + ### Delete historical messages from the server unidirectionally Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx index 50da44ce6..ba90f0a5d 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx @@ -4,6 +4,7 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. - `asyncFetchConversationsFromServer`: Retrieves a list of conversations stored on the server. - `asyncFetchHistoryMessage`: Retrieves the historical messages in the specified conversation from the server. +- `asyncFetchHistoryMessages`: Retrieves historical messages of a conversation from the server according to `FetchMessageOption`, the parameter configuration class for retrieving historical messages. - `removeMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `deleteConversationFromServer`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx index e66c86094..0a3e7dee3 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx @@ -4,6 +4,7 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. - `fetchConversationListFromServer`: Retrieves a list of conversations stored on the server. - `fetchHistoryMessages`: Retrieves the historical messages in the specified conversation from the server. +- `fetchHistoryMessagesByOption`: Retrieves historical messages of a conversation from the server according to `FetchMessageOptions`, the parameter configuration class for retrieving historical messages. - `deleteRemoteMessagesBefore`/`deleteRemoteMessagesWithIds`: Deletes historical messages from the server unidirectionally. - `deleteRemoteConversation`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx index b856bc398..c9c2409a5 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx @@ -4,6 +4,7 @@ The Chat SDK uses `IChatManager` to retrieve historical messages from the server - `GetConversationsFromServerWithPage`: Retrieve conversations stored on the server with pagination. - `FetchHistoryMessagesFromServer`: Retrieve the historical messages in the specified conversation from the server. +- `FetchHistoryMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. - `RemoveMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `DeleteConversationFromServer`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx index b26a75199..32abaced1 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx @@ -2,7 +2,7 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. Followings are the core methods: -- `getConversationList`: Retrieves a list of conversations stored on the server. +- `getServerConversations`: Retrieves a list of conversations stored on the server with pagination. - `getHistoryMessages`: Retrieves the historical messages in the specified conversation from the server. - `removeHistoryMessages`: Deletes historical messages from the server unidirectionally. - `deleteConversation`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx index ad33000ca..dc9e665a8 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx @@ -4,6 +4,7 @@ The Chat SDK uses `IChatManager` to retrieve historical messages from the server - `GetConversationsFromServerWithPage`: Retrieve conversations stored on the server with pagination. - `FetchHistoryMessagesFromServer`: Retrieve the historical messages in the specified conversation from the server. +- `FetchHistoryMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. - `RemoveMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `DeleteConversationFromServer`: Deletes conversations and their historical messages from the server. From 3d206def47c7d22b5158843a69d1937050b905ba Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 9 Nov 2023 20:32:58 +0200 Subject: [PATCH 21/37] October features --- .../project-implementation/android.mdx | 106 ------------------ .../project-implementation/flutter.mdx | 44 -------- .../project-implementation/ios.mdx | 30 ----- .../project-implementation/react-native.mdx | 53 --------- .../project-implementation/unity.mdx | 64 ----------- .../project-implementation/web.mdx | 44 -------- .../project-implementation/windows.mdx | 66 ----------- .../project-implementation/android.mdx | 4 - .../project-implementation/react-native.mdx | 2 +- .../project-implementation/web.mdx | 2 +- .../project-implementation/windows.mdx | 4 +- 11 files changed, 4 insertions(+), 415 deletions(-) diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx index 05e2bce55..e168cb860 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/android.mdx @@ -128,112 +128,6 @@ public void checkIfInGroupWhiteList(final String groupId, ValueCallBack public void fetchGroupWhiteList(final String groupId, final ValueCallBack> callBack); ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```java - Map attributeMap = new HashMap<>(); - attributeMap.put("nickName", nickName); - - ChatClient.getInstance().groupManager().asyncSetGroupMemberAttributes( - groupId, - userId, - attributeMap, - new CallBack() { - @Override - public void onSuccess() { - // Indent content inside the method - } - - @Override - public void onError(int code, String error) { - // Indent content inside the method - } - } - ); - ``` - -1. Retrieve all attributes of a group member: - - ```java - ChatClient.getInstance().groupManager().asyncFetchGroupMemberAllAttributes( - groupId, - userId, - new ValueCallBack>>() { - @Override - public void onSuccess(Map> value) { - if (value != null) { - Map attributeMap = value.get(userId); - } - } - - @Override - public void onError(int code, String error) { - } - } - ); - ``` - -1. Retrieve selected attributes of specific group members: - - ```java - List keyList = new ArrayList<>(); - keyList.add("nickName"); - - List userIds = new ArrayList<>(); - userIds.add("Tom"); - userIds.add("Jack"); - - ChatClient.getInstance().groupManager().asyncFetchGroupMembersAttributes( - groupId, - userIds, - keyList, - new ValueCallBack>>() { - @Override - public void onSuccess(Map> value) { - if (value != null) { - for (String user : userIds) { - Map map = value.get(user); - if (map != null) { - //…… - } - } - } - } - - @Override - public void onError(int code, String error) { - } - } - ); - ``` - -1. Receive notification of changes in group member attributes: - - ```java - // Create a GroupChangeListener object - GroupChangeListener groupChangeListener = new GroupChangeListener() { - // …… - - @Override - public void onGroupMemberAttributeChanged(String groupId, String userId, Map attribute, String from) { - if (attribute != null && attribute.size() > 0) { - // EMLog.d(TAG,"onGroupMemberAttributeChanged: " + groupId +" - "+ attribute.toString()); - } - } - }; - - // Add a group change listener: - ChatClient.getInstance().groupManager().addGroupChangeListener(groupChangeListener); - - // Remove a group change listener: - ChatClient.getInstance().groupManager().removeGroupChangeListener(groupChangeListener); - - ``` - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx index a65c450ba..8bb896fbf 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/flutter.mdx @@ -260,50 +260,6 @@ try { } ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```dart - await ChatClient.getInstance.groupManager.setMemberAttributes( - groupId: groupId, - userId: userId, - attributes: {'key': 'value'}, - ); - ``` - -1. Retrieve attributes of group members: - - ```dart - Map attribute = - await ChatClient.getInstance.groupManager.fetchMemberAttributes( - groupId: 'groupId', - userId: 'userId', - ); - ``` - - -1. Receive notification of changes in group member attributes: - - ```dart - // Add an event handler - ChatClient.getInstance.groupManager.addEventHandler( - 'UNIQUE_HANDLER_ID', - ChatGroupEventHandler( - onAttributesChangedOfGroupMember: - (groupId, userId, attributes, operatorId) {}, - ), - ); - - // ... - - // Remove an event handler - ChatClient.getInstance.groupManager.removeEventHandler('UNIQUE_HANDLER_ID'); - ``` - - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx index faafcf87a..9421e18e7 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/ios.mdx @@ -160,36 +160,6 @@ Refer to the following sample code to manage the chat group allow list: [[AgoraChatClient sharedClient].groupManager getGroupWhiteListFromServerWithId:@"groupID" error:nil]; ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```objective-c - [AgoraChatClient.sharedClient.groupManager setMemberAttribute:@"groupId" - userId:@"userId" - attributes:@{@"key":@"value"} - completion:^(AgoraChatError * _Nullable error) { - }]; - ``` - -1. Retrieve attributes of group members: - - ```objective-c - [AgoraChatClient.sharedClient.groupManager fetchMembersAttributes:@"groupId" userIds:@[@"userId1",@"userId2"] keys:@[@"key1",@"key2"] completion:^(NSDictionary *> * _Nullable attributes, AgoraChatError * _Nullable error) { - - }]; - ``` - - -1. Receive notification of changes in group member attributes: - - ```objective-c - - (void)onAttributesChangedOfGroupMember:(NSString *)groupId userId:(NSString *)userId attributes:(NSDictionary *)attributes operatorId:(NSString *)operatorId { - } - ``` - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx index 45fdfb1ed..82f7d92cb 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/react-native.mdx @@ -302,59 +302,6 @@ ChatClient.getInstance() }); ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```typescript - // groupId: The group ID. - // member: The user ID of the group member. - // attributes: The custom attributes to set. - ChatClient.getInstance() - .groupManager.setMemberAttribute(groupId, member, attributes) - .then(() => { - console.log("set group members attributes success."); - }) - .catch((reason) => { - console.log("set group members attributes fail.", reason); - }); - - ``` - -1. Retrieve attributes of group members: - - ```typescript - // groupId: The group ID. - // member: The user ID of the group member. - ChatClient.getInstance() - .groupManager.fetchMemberAttributes(groupId, member) - .then((attributes: Record | undefined) => { - console.log("get group members attributes success.", attributes); - }) - .catch((reason) => { - console.log("get group members attributes fail.", reason); - }); - ``` - - -1. Receive notification of changes in group member attributes: - - ```typescript - onMemberAttributesChanged(params: { - groupId: string; - member: string; - attributes: any; - operator: string; - }): void { - console.log(`${QuickTestScreenBase.TAG}: onStateChanged:`, params); - this.that.setState({ - recvResult: `onMemberAttributesChanged: ` + params, - }); - } - ``` - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx index bb894b37b..15f425aca 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/unity.mdx @@ -292,70 +292,6 @@ SDKClient.Instance.GroupManager.GetGroupWhiteListFromServer(currentGroupId, call )); ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```csharp - Dictionary dict = new Dictionary(); - dict.Add("key", "value"); - - SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( - onSuccess: () => - { - Console.WriteLine($"SetMemberAttributes success."); - }, - onError: (code, desc) => - { - Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); - } - )); - - ``` - -1. Retrieve attributes of group members: - - ```csharp - List userList = new List(); - userList.Add("user"); - - // keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. - List keyList = new List(); - keyList.Add("key"); - - SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( - onSuccess: (dict) => - { - - }, - onError: (code, desc) => - { - - } - )); - ``` - -1. Receive notification of changes in group member attributes: - - ```csharp - // Inherit and implement `IGroupManagerDelegate`. - public class GroupManagerDelegate : IGroupManagerDelegate { - - public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) - { - } - } - - // Add a delegate. - GroupManagerDelegate adelegate = new GroupManagerDelegate(); - SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); - - // Remove the delegate when it is unnecessary. - SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); - ``` - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx index 570f30b89..16b2d8090 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/web.mdx @@ -195,50 +195,6 @@ let options = { conn.getGroupAllowlist(options).then(res => console.log(res)); ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```js - let options = { - groupId: 'groupId', - userId: 'userId', - memberAttributes: { - key: 'value' - }, - } - - connection.setGroupMemberAttributes(options).then((res) => { - console.log(res) - }).catch((e) => { - console.log(e) - }) - ``` - -1. Retrieve attributes of group members: - - ```js - let options = { - groupId: 'groupId', - userId: 'userId' - } - - connection.getGroupMemberAttributes(options).then((res) => { - console.log(res) - }).catch((e) => { - console.log(e) - }) - ``` - -1. Receive notification of changes in group member attributes: - - ```js - case "memberAttributesUpdate": - break; - ``` - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx index d3f48b4ea..e5b7ae531 100644 --- a/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/chat-group/manage-group-members/project-implementation/windows.mdx @@ -292,72 +292,6 @@ SDKClient.Instance.GroupManager.GetGroupWhiteListFromServer(currentGroupId, call )); ``` -### Manage custom attributes of group members - -Custom attributes enable you to manage information about group members such as member ID, identity, avatar, and nickname. Each custom attribute is in the key-value form. - -1. Set group member attributes: - - ```csharp - Dictionary dict = new Dictionary(); - dict.Add("key", "value"); - - SDKClient.Instance.GroupManager.SetMemberAttributes(groupId, userId, dict, new CallBack( - onSuccess: () => - { - Console.WriteLine($"SetMemberAttributes success."); - }, - onError: (code, desc) => - { - Console.WriteLine($"SetMemberAttributes failed, code:{code}, desc:{desc}"); - } - )); - - ``` - -1. Retrieve attributes of group members: - - ```csharp - List userList = new List(); - userList.Add("user"); - - // keyList: The array of keys for custom attributes of group members. If you pass in no value or an empty array, this method retrieves all custom attributes of these group members. - List keyList = new List(); - keyList.Add("key"); - - SDKClient.Instance.GroupManager.FetchMemberAttributes(groupId, userList, keyList, new ValueCallBack>>( - onSuccess: (dict) => - { - - }, - onError: (code, desc) => - { - - } - )); - ``` - -1. Receive notification of changes in group member attributes: - - ```csharp - // Inherit and implement `IGroupManagerDelegate` - public class GroupManagerDelegate : IGroupManagerDelegate { - - public void OnUpdateMemberAttributesFromGroup(string groupId, string userId, Dictionary attributes, string from) - { - - } - } - - // Add a delegate - GroupManagerDelegate adelegate = new GroupManagerDelegate(); - SDKClient.Instance.GroupManager.AddGroupManagerDelegate(adelegate); - - // Remove the delegate when it is no longer required - SDKClient.Instance.GroupManager.RemoveGroupManagerDelegate(adelegate); - ``` - - ### Listen for chat group events For details, see [Chat Group Events](../chat-group/manage-chat-groups#listen-for-chat-group-events). diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 1e6c73c57..0d7470b64 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -85,10 +85,6 @@ ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(conversationId, Using `FetchMessageOption` to configure the time range parameters, the `asyncFetchHistoryMessages` method can retrieve historical messages of a conversation from the server for a specific range of time. -If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. - -The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. - ```java String conversationId=" "; Conversation.ConversationType type=Conversation.ConversationType.Chat; diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index bb010655c..8bdaa1220 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -1,6 +1,6 @@ -## Retrieve a list of conversations from the server +### Retrieve a list of conversations from the server Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index e7b955057..8b44c59b1 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -1,6 +1,6 @@ -## Retrieve a list of conversations from the server +### Retrieve a list of conversations from the server Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 52d300d5f..ca8d5a967 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -36,8 +36,6 @@ After retrieving conversations, you can use these methods to retrieve historical You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. -#### Retrieve historical messages by pagination - If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: @@ -50,6 +48,8 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +#### Retrieve historical messages by pagination + ```csharp SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, type, startId, pageSize, new ValueCallBack>( // Fetching historical messages succeeds. From a4de4c8e9b7887bea651b4dab25b2f13b1e451f5 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 9 Nov 2023 21:01:29 +0200 Subject: [PATCH 22/37] October features --- .../project-implementation/web.mdx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 8b44c59b1..eff2a2e9b 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -33,6 +33,8 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +#### Retrieve historical messages by pagination + ```javascript var options = { // The ID of the peer user, or chat group, or chat room, depending on the chat type. @@ -56,6 +58,24 @@ WebIM.conn.getHistoryMessages(options).then((res)=>{ }) ``` +#### Retrieve historical messages by time range + +```javascript +connection.getHistoryMessages({ + targetId: 'targetId', // The user ID of the peer user for one-to-one chat or group ID for group chat. + chatType: 'groupChat', // The chat type: `singleChat` for one-to-one chat or `groupChat` for group chat. + pageSize: 20, // The number of messages to retrieve per page. The value range is [1,50] and the default value is 20. + searchDirection: 'down', // The message search direction: `up` means to retrieve messages in the descending order of the message timestamp and `down` means to retrieve messages in the ascending order of the message timestamp. + searchOptions: { + from: 'message sender userID', // The user ID of the message sender. This parameter is used only for group chat. + msgTypes: ['txt'], // An array of message types for query. If no value is passed in, all types of message will be queried. + startTime: new Date('2023,11,9').getTime(), // The start timestamp for query. The unit is millisecond. + endTime: new Date('2023,11,10').getTime(), // The end timestamp for query. The unit is millisecond. + }, +}); +``` + + ### Delete historical messages from the server unidirectionally Call `removeHistoryMessages` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. From 0279302cf413a29e8d2e39eac68ce539c35e9bb4 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 9 Nov 2023 21:14:33 +0200 Subject: [PATCH 23/37] October features --- shared/chat-sdk/restful-api/_message-management.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index 1e5d81ace..57faa43c4 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1444,7 +1444,7 @@ The fields of `bodies` for different message types vary: Once a message is sent, you can call this API to recall it. This API recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../get-started/enable). For each App Key, the call frequency limit of this method is 100 per second. From 52971d313f655aba9aa21b52e49ee4bb944ed7ec Mon Sep 17 00:00:00 2001 From: atovpeko Date: Tue, 14 Nov 2023 14:27:48 +0200 Subject: [PATCH 24/37] Comments, react native code sample --- .../project-implementation/android.mdx | 8 ++++++++ .../project-implementation/flutter.mdx | 8 ++++++++ .../project-implementation/ios.mdx | 8 ++++++++ .../project-implementation/react-native.mdx | 8 ++++++++ .../project-implementation/unity.mdx | 8 ++++++++ .../project-implementation/web.mdx | 8 ++++++++ .../project-implementation/windows.mdx | 10 +++++++++- shared/chat-sdk/reference/_limitations.mdx | 19 +++++++++++++++---- .../restful-api/_user-system-registration.mdx | 3 --- 9 files changed, 72 insertions(+), 8 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx index 844154e7f..9fac34302 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx @@ -56,6 +56,14 @@ ChatClient.getInstance().chatManager().asyncPinConversation(conversationId, true ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```java diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx index f0f24450e..ab234e3b8 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx @@ -69,6 +69,14 @@ ChatClient.getInstance.chatManager.pinConversation( ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```dart diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx index 25c25b994..24407386c 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx @@ -57,6 +57,14 @@ Refer to the following code example to pin a conversation: ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```objc diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx index d7958d3ed..f59fee604 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx @@ -92,6 +92,14 @@ ChatClient.getInstance() ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```typescript diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx index e0c6fa109..a6e4f48a8 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx @@ -65,6 +65,14 @@ SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx index b6c260343..213aadd66 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx @@ -10,6 +10,14 @@ connection.pinConversation({conversationId:'conversationId', conversationType: ' ### Retrieve the pinned conversations from the server with pagination +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + Refer to the following code example to get a list of pinned conversations from the server with pagination: ```javaScript diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx index 8233bc3aa..cb8f2d4e4 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx @@ -64,7 +64,15 @@ SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( ### Retrieve the pinned conversations from the server -Refer to the following code example to get a list of pinned conversations from the server: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: + +1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. +1. Pinned conversation without any messages, that is, empty conversations. +1. Unpinned conversations. + +The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. + +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp int limit = 10; diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index 3d50f2b3b..e461acbbb 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -2,7 +2,7 @@ This page introduces the usage limits of Chat, including limits to the user, the ### User attributes -The user attributes [UserInfo](https://hyphenateinc.github.io/android_reference/classio_1_1agora_1_1chat_1_1_user_info.html) Includes the user avatar, nickname, email address, and so on. The total length of the user information for one user must be 2 KB or less, and the total length for all users under an app must be within 10 GB or less. +The user attributes [UserInfo](https://hyphenateinc.github.io/android_reference/classio_1_1agora_1_1chat_1_1_user_info.html) include the user avatar, nickname, email address, and so on. The total length of the user information for one user must be 2 KB or less, and the total length for all users under an app must be within 10 GB or less. ### Message length @@ -20,7 +20,7 @@ The length limits of the different types of messages are as follows: | Customized message | 5 KB | createSendMessage | -### Group-related limits +### Group-related limitations **Group attributes** @@ -33,7 +33,15 @@ When a group Date: Tue, 14 Nov 2023 14:28:01 +0200 Subject: [PATCH 25/37] Comments, react native code sample --- .../project-implementation/react-native.mdx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 8bdaa1220..9d53e50b6 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -36,6 +36,8 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. +#### Retrieve historical messages by pagination + ```typescript // Specify the conversation ID. const convId = "convId"; @@ -58,6 +60,23 @@ ChatClient.getInstance() }) ``` +#### Retrieve historical messages for a time range + +```typescript +ChatClient.getInstance() + .chatManager.fetchHistoryMessagesByOptions(convId, convType, { + cursor: cursor, + pageSize: pageSize, + options: options as ChatFetchMessageOptions, + }) + .then((result) => { + console.log("get history message success", result); + }) + .catch((reason) => { + console.log("get history message fail.", reason); + }); +``` + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServerWithTimestamp` or `removeMessagesFromServerWithMsgIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. From 3b9497378cefb46d6335d32d5af0583b7d36794a Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 16 Nov 2023 12:17:34 +0200 Subject: [PATCH 26/37] review updates --- .../manage-messages/project-implementation/android.mdx | 6 ++++-- .../manage-messages/project-implementation/flutter.mdx | 6 ++++-- .../messages/manage-messages/project-implementation/ios.mdx | 6 ++++-- .../manage-messages/project-implementation/react-native.mdx | 6 ++++-- .../manage-messages/project-implementation/unity.mdx | 6 ++++-- .../messages/manage-messages/project-implementation/web.mdx | 4 ++-- .../manage-messages/project-implementation/windows.mdx | 6 ++++-- .../project-implementation/android.mdx | 2 +- .../project-implementation/flutter.mdx | 2 +- .../send-receive-messages/project-implementation/ios.mdx | 2 +- .../project-implementation/react-native.mdx | 2 +- .../send-receive-messages/project-implementation/unity.mdx | 2 +- .../send-receive-messages/project-implementation/web.mdx | 2 +- .../project-implementation/windows.mdx | 2 +- shared/chat-sdk/reference/_limitations.mdx | 2 +- 15 files changed, 34 insertions(+), 22 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx index 9fac34302..76c27602c 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx @@ -39,6 +39,8 @@ ChatClient.getInstance().chatManager().getUnreadMessageCount(); ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```java @@ -56,7 +58,7 @@ ChatClient.getInstance().chatManager().asyncPinConversation(conversationId, true ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -64,7 +66,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```java String cursor = ""; diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx index ab234e3b8..50c709214 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx @@ -57,6 +57,8 @@ int unreadCount = ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```dart @@ -69,7 +71,7 @@ ChatClient.getInstance.chatManager.pinConversation( ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -77,7 +79,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```dart String? cursor; diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx index 24407386c..ee0ed2f4f 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx @@ -46,6 +46,8 @@ for (AgoraConversation *conversation in conversations) { ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```objc @@ -57,7 +59,7 @@ Refer to the following code example to pin a conversation: ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -65,7 +67,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```objc [AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx index f59fee604..68d61b137 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx @@ -75,6 +75,8 @@ ChatClient.getInstance() ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```typescript @@ -92,7 +94,7 @@ ChatClient.getInstance() ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -100,7 +102,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```typescript ChatClient.getInstance() diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx index a6e4f48a8..bcbf41a64 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx @@ -47,6 +47,8 @@ SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```csharp @@ -65,7 +67,7 @@ SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -73,7 +75,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp int limit = 10; diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx index 213aadd66..26f76a8b6 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx @@ -10,7 +10,7 @@ connection.pinConversation({conversationId:'conversationId', conversationType: ' ### Retrieve the pinned conversations from the server with pagination -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -18,7 +18,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```javaScript connection.getServerPinnedConversations({pageSize:50, cursor: ''}) diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx index cb8f2d4e4..5b1cb781d 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx @@ -47,6 +47,8 @@ SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ### Pin a conversation +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + Refer to the following code example to pin a conversation: ```csharp @@ -64,7 +66,7 @@ SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( ### Retrieve the pinned conversations from the server -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Thus, end users can pin up to 50 conversations. This API sorts all the conversations based on the following order: +End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: 1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. 1. Pinned conversation without any messages, that is, empty conversations. @@ -72,7 +74,7 @@ The Limit parameter specifies the number of conversations each API call can retu The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. -Refer to the following code example to get a list of pinned conversations from the server with pagination: +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp int limit = 10; diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index d26311470..2c6f1c6c9 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -340,7 +340,7 @@ message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attri ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 119fd68aa..364067733 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -278,7 +278,7 @@ ChatClient.getInstance.chatManager.addEventHandler( ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 4eaca21fc..7b21657bb 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -359,7 +359,7 @@ message.chatType = AgoraChatTypeChat; ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index fa3774e22..8451e99b7 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -208,7 +208,7 @@ onMessagesRecalled(messages: ChatMessage[]): void; ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 071bd5d19..85d38046a 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -402,7 +402,7 @@ if (found) { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 7b1265558..8c4d697bf 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -504,7 +504,7 @@ function sendPrivateText() { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index be9e5a840..04aa6e2ff 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -402,7 +402,7 @@ if (found) { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index e461acbbb..064f45c2c 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -72,7 +72,7 @@ This feature has the following limitations: * For a group chat, regular group members can only edit message sent by themselves, but the group owner and admins can also edit messages sent by regular group members. The message sender remains unchanged regardless of the message edit operator. * Supported message types: text only. * Supported use case: One-on-one chat group. Does not support Chatroom. -* End users can recall and messages that were sent up to 7 days ago. +* End users can recall and modify messages that were sent up to 7 days ago. * Agora supports editing the same message up to 10 times. ### Storage limitations From 5a4f0b8d503682b6ed9b948f5961fdf875122ee4 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 16 Nov 2023 17:59:38 +0200 Subject: [PATCH 27/37] review comments --- .../client-api/messages/retrieve-messages.mdx | 2 +- assets/images/chat/message-recall.png | Bin 0 -> 287049 bytes .../project-implementation/android.mdx | 60 ------------------ .../project-implementation/flutter.mdx | 36 ----------- .../project-implementation/index.mdx | 2 - .../project-implementation/ios.mdx | 32 ---------- .../project-implementation/react-native.mdx | 42 ------------ .../project-implementation/unity.mdx | 54 ---------------- .../project-implementation/web.mdx | 27 -------- .../project-implementation/windows.mdx | 53 ---------------- .../project-implementation/android.mdx | 58 ++++++++++++++++- .../project-implementation/flutter.mdx | 34 +++++++++- .../project-implementation/ios.mdx | 30 ++++++++- .../project-implementation/react-native.mdx | 41 +++++++++++- .../project-implementation/unity.mdx | 52 ++++++++++++++- .../project-implementation/web.mdx | 24 ++++++- .../project-implementation/windows.mdx | 51 ++++++++++++++- .../project-implementation/android.mdx | 16 ++++- .../project-implementation/flutter.mdx | 16 ++++- .../project-implementation/ios.mdx | 17 ++++- .../project-implementation/react-native.mdx | 16 ++++- .../project-implementation/unity.mdx | 16 ++++- .../project-implementation/web.mdx | 16 ++++- .../project-implementation/windows.mdx | 16 ++++- .../restful-api/_message-management.mdx | 4 +- 25 files changed, 386 insertions(+), 329 deletions(-) create mode 100644 assets/images/chat/message-recall.png delete mode 100644 shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx diff --git a/agora-chat/client-api/messages/retrieve-messages.mdx b/agora-chat/client-api/messages/retrieve-messages.mdx index a9d3f0870..91f241735 100644 --- a/agora-chat/client-api/messages/retrieve-messages.mdx +++ b/agora-chat/client-api/messages/retrieve-messages.mdx @@ -1,5 +1,5 @@ --- -title: 'Retrieve messages' +title: 'Manage server-side messages' sidebar_position: 4 type: docs description: > diff --git a/assets/images/chat/message-recall.png b/assets/images/chat/message-recall.png new file mode 100644 index 0000000000000000000000000000000000000000..abab20a65fcfcdfc9f7088a245e273b7bdb50e44 GIT binary patch literal 287049 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
    m%BzC$6T`Nqw0=%;j+3x+zm< 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
    ^{C&r8f{Rldt=+#r|h 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 conversations = new ArrayList<>(); -doAsyncFetchPinnedConversationsFromServer(limit,cursor,conversations); - -private void doAsyncFetchPinnedConversationsFromServer(final int limit, final String cursor,List conversations){ - ChatClient.getInstance().chatManager().asyncFetchPinnedConversationsFromServer(limit, cursor, new ValueCallBack>() { - @Override - public void onSuccess(CursorResult value) { - if (value != null) { - List list = value.getData(); - if (list != null && list.size() > 0) { - conversations.addAll(list); - } - String newCursor = value.getCursor(); - if( !TextUtils.isEmpty(newCursor)) { - doAsyncFetchPinnedConversationsFromServer(limit, newCursor, conversations); - } - } - } - - @Override - public void onError(int error, String errorMsg) { - } - }); -} -``` - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx index 50c709214..dd2013d78 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/flutter.mdx @@ -55,42 +55,6 @@ int unreadCount = await ChatClient.getInstance.chatManager.getUnreadMessageCount(); ``` -### Pin a conversation - -To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. - -Refer to the following code example to pin a conversation: - -```dart -ChatClient.getInstance.chatManager.pinConversation( - conversationId: conversationId, - isPinned: isPinned, -); -``` - - -### Retrieve the pinned conversations from the server with pagination - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```dart -String? cursor; -int pageSize = 10; -ChatCursorResult result = - await ChatClient.getInstance.chatManager.fetchPinnedConversations( - cursor: cursor, - pageSize: pageSize, -); -``` - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx index 6c3a2630d..a0f59ac2a 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/index.mdx @@ -1,6 +1,5 @@ import Android from './android.mdx'; import Ios from './ios.mdx'; -import Web from './web.mdx'; import Flutter from './flutter.mdx'; import ReactNative from './react-native.mdx'; import Windows from './windows.mdx'; @@ -8,7 +7,6 @@ import Unity from './unity.mdx'; - diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx index ee0ed2f4f..b64033fa0 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/ios.mdx @@ -44,38 +44,6 @@ for (AgoraConversation *conversation in conversations) { ``` -### Pin a conversation - -To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. - -Refer to the following code example to pin a conversation: - -```objc -[AgoraChatClient.sharedClient.chatManager pinConversation:@"conversationId" isPinned:YES completionBlock:^(AgoraChatError * _Nullable error) { - -}]; -``` - - -### Retrieve the pinned conversations from the server with pagination - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```objc -[AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { - -}]; -``` - - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx index 68d61b137..61c58d76d 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/react-native.mdx @@ -73,48 +73,6 @@ ChatClient.getInstance() }); ``` -### Pin a conversation - -To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. - -Refer to the following code example to pin a conversation: - -```typescript -// isPinned: Sets whether to pin a conversation. -ChatClient.getInstance() - .chatManager.pinConversation(convId, isPinned) - .then(() => { - console.log("pin conversions success"); - }) - .catch((reason) => { - console.log("pin conversions fail.", reason); - }); -``` - - -### Retrieve the pinned conversations from the server with pagination - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```typescript -ChatClient.getInstance() - .chatManager.fetchPinnedConversationsFromServerWithCursor(cursor, pageSize) - .then(() => { - console.log("get conversions success"); - }) - .catch((reason) => { - console.log("get conversions fail.", reason); - }); -``` - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx index bcbf41a64..ad480c6c7 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/unity.mdx @@ -45,60 +45,6 @@ Refer to the following code example to retrieve the count of all unread messages SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ``` -### Pin a conversation - -To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. - -Refer to the following code example to pin a conversation: - -```csharp -SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( - onSuccess: () => - { - - }, - onError: (code, desc) => - { - - } -)); -``` - - -### Retrieve the pinned conversations from the server with pagination - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```csharp -int limit = 10; -string cursor = ""; -bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. -SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( - onSuccess: (result) => - { - // Traverse the obtained conversation list - foreach (var conv in result.Data) - { - - } - // The cursor for the next query - string nextCursor = result.Cursor; - }, - onError: (code, desc) => - { - - } -)); -``` - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx deleted file mode 100644 index 26f76a8b6..000000000 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/web.mdx +++ /dev/null @@ -1,27 +0,0 @@ - - -### Pin a conversation - -Refer to the following code example to pin a conversation: - -```javaScript -connection.pinConversation({conversationId:'conversationId', conversationType: 'singleChat', isPinned: true}) -``` - -### Retrieve the pinned conversations from the server with pagination - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```javaScript -connection.getServerPinnedConversations({pageSize:50, cursor: ''}) -``` - - \ No newline at end of file diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx index 5b1cb781d..c8b860bd8 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/windows.mdx @@ -45,59 +45,6 @@ Refer to the following code example to retrieve the count of all unread messages SDKClient.Instance.ChatManager.GetUnreadMessageCount(); ``` -### Pin a conversation - -To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. - -Refer to the following code example to pin a conversation: - -```csharp -SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( - onSuccess: () => - { - - }, - onError: (code, desc) => - { - - } -)); -``` - -### Retrieve the pinned conversations from the server - -End users can pin up to 50 conversations. This API sorts all the conversations based on the following order: - -1. Pinned conversations with recently received messages. The more recent the messages are, the higher the conversation is sorted/ranked so that it appears on the top of the UI. -1. Pinned conversation without any messages, that is, empty conversations. -1. Unpinned conversations. - -The Agora Chat servers store the pinned/unpinned status of active conversations for 7 days, regardless of the package subscription. - -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: - -```csharp -int limit = 10; -string cursor = ""; -bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. -SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( - onSuccess: (result) => - { - // Traverse the obtained conversation list - foreach (var conv in result.Data) - { - - } - // The cursor for the next query - string nextCursor = result.Cursor; - }, - onError: (code, desc) => - { - - } -)); -``` - ### Mark unread messages as read Refer to the following code example to mark the specified messages as read: diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 0d7470b64..e8175dee2 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java @@ -124,6 +124,62 @@ private void doAsyncFetchHistoryMessages(String conversationId, } ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```java +ChatClient.getInstance().chatManager().asyncPinConversation(conversationId, true, new CallBack() { + @Override + public void onSuccess() { + } + + @Override + public void onError(int code, String error) { + } +}); +``` + + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```java +String cursor = ""; +int limit = 40; +List conversations = new ArrayList<>(); +doAsyncFetchPinnedConversationsFromServer(limit,cursor,conversations); + +private void doAsyncFetchPinnedConversationsFromServer(final int limit, final String cursor,List conversations){ + ChatClient.getInstance().chatManager().asyncFetchPinnedConversationsFromServer(limit, cursor, new ValueCallBack>() { + @Override + public void onSuccess(CursorResult value) { + if (value != null) { + List list = value.getData(); + if (list != null && list.size() > 0) { + conversations.addAll(list); + } + String newCursor = value.getCursor(); + if( !TextUtils.isEmpty(newCursor)) { + doAsyncFetchPinnedConversationsFromServer(limit, newCursor, conversations); + } + } + } + + @Override + public void onError(int error, String errorMsg) { + } + }); +} +``` + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index a4f96fea7..ee64bfbfb 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. +Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```dart @@ -95,6 +95,38 @@ ChatCursorResult result = ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```dart +ChatClient.getInstance.chatManager.pinConversation( + conversationId: conversationId, + isPinned: isPinned, +); +``` + + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```dart +String? cursor; +int pageSize = 10; +ChatCursorResult result = + await ChatClient.getInstance.chatManager.fetchPinnedConversations( + cursor: cursor, + pageSize: pageSize, +); +``` + ### Delete historical messages from the server unidirectionally Call `deleteRemoteMessagesBefore` or `deleteRemoteMessagesWithIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 874156fb1..b24840c1f 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```objective-c @@ -54,6 +54,34 @@ AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOptio }]; ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```objc +[AgoraChatClient.sharedClient.chatManager pinConversation:@"conversationId" isPinned:YES completionBlock:^(AgoraChatError * _Nullable error) { + +}]; +``` + + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```objc +[AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { + +}]; +``` + + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServerWithTimeStamp` or `removeMessagesFromServerMessageIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 9d53e50b6..fdc2a75c3 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java @@ -77,6 +77,45 @@ ChatClient.getInstance() }); ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```typescript +// isPinned: Sets whether to pin a conversation. +ChatClient.getInstance() + .chatManager.pinConversation(convId, isPinned) + .then(() => { + console.log("pin conversions success"); + }) + .catch((reason) => { + console.log("pin conversions fail.", reason); + }); +``` + + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```typescript +ChatClient.getInstance() + .chatManager.fetchPinnedConversationsFromServerWithCursor(cursor, pageSize) + .then(() => { + console.log("get conversions success"); + }) + .catch((reason) => { + console.log("get conversions fail.", reason); + }); +``` + + ### Delete historical messages from the server unidirectionally Call `removeMessagesFromServerWithTimestamp` or `removeMessagesFromServerWithMsgIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index ddcd7fd4c..5504a117e 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp @@ -92,6 +92,56 @@ SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, )); ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```csharp +SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( + onSuccess: () => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```csharp +int limit = 10; +string cursor = ""; +bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next query + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); +``` + ### Delete historical messages from the server unidirectionally Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index eff2a2e9b..2d6b60688 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. +Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user.
    Do not use mixed upper-case.
    @@ -75,6 +75,28 @@ connection.getHistoryMessages({ }); ``` +### Pin a conversation + +Refer to the following code example to pin a conversation: + +```javaScript +connection.pinConversation({conversationId:'conversationId', conversationType: 'singleChat', isPinned: true}) +``` + +### Retrieve the pinned conversations from the server with pagination + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```javaScript +// pageSize: The number of sessions returned per page. The value range is [1,50]。 +// cursor:The cursor position to start getting data. If an empty string ('') is passed, the SDK will start querying from the latest pinned session. +connection.getServerPinnedConversations({pageSize:50, cursor: ''}) +``` + ### Delete historical messages from the server unidirectionally diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index ca8d5a967..bf4d58faf 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). If there is no message in conversations, the SDK returns the conversation list in the reverse chronological order of when conversations are created. Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp @@ -89,6 +89,55 @@ SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, )); ``` +### Pin a conversation + +To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login scenario, if you pin or unpin a conversation, other login devices will receive the `CONVERSATION_PINNED` or `CONVERSATION_UNPINNED` events. + +Refer to the following code example to pin a conversation: + +```csharp +SDKClient.Instance.ChatManager.PinConversation(convId, isPinned, new CallBack( + onSuccess: () => + { + + }, + onError: (code, desc) => + { + + } +)); +``` + +### Retrieve the pinned conversations from the server + +End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned. + +Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. + +The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: + +```csharp +int limit = 10; +string cursor = ""; +bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next query + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); +``` + ### Delete historical messages from the server unidirectionally Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 2c6f1c6c9..04e8cafaa 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -69,7 +69,9 @@ ChatClient.getInstance().chatManager().removeMessageListener(msgListener); After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```java try { @@ -377,7 +379,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 364067733..70dd57fa3 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -257,7 +257,9 @@ String? thumbnailLocalPath = imgBody.thumbnailLocalPath; After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```dart try { @@ -313,7 +315,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 7b21657bb..1ecaad913 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -69,7 +69,10 @@ When a message arrives, the recipient receives an `messagesDidReceive` callback. ### Recall a message After a message is sent, you can recall it. The `recallMessageWithMessageId` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). + +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```objective-c [[AgoraChatClient sharedClient].chatManager recallMessageWithMessageId:@"messageId" completion:^(AgoraChatError *aError) { @@ -387,7 +390,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index 8451e99b7..d87a124b2 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -188,7 +188,9 @@ ChatClient.getInstance().chatManager.removeAllMessageListener(); After a message is sent, you can recall it. The `recallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```typescript ChatClient.getInstance() @@ -240,7 +242,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 85d38046a..32601d84a 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -61,7 +61,9 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```csharp // Call `RecallMessage` to recall the message. @@ -441,7 +443,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 8c4d697bf..129db8e8f 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -121,7 +121,9 @@ WebIM.conn.addEventHandler("eventName",{ After a message is sent, you can recall it. The `recallMessage` method recalls a message saved on the server, whether it is a historical message, offline message or a roaming message. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```javascript /** @@ -554,7 +556,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index 04aa6e2ff..bfce1f009 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -61,7 +61,9 @@ SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); After a message is sent, you can recall it. The `RecallMessage` method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -You can recall a message sent within two minutes by default. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) ```csharp // Call `RecallMessage` to recall the message. @@ -441,7 +443,17 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: +Every end user or chat group member may edit messages that they have sent. + +The process of modifying a message is as follows: + +1. The user calls the API of the SDK to modify a message. +1. The message stored on the server is called back to the SDK after the modification is successful. +1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. + +There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. + +In the modified message, the message ID remains unchanged. Only the message content is edited and the following items are added: * The operator ID of the user performing the action. * The operation time that indicates when the message was edited. diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index 57faa43c4..a281b3f75 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -1444,7 +1444,9 @@ The fields of `bodies` for different message types vary: Once a message is sent, you can call this API to recall it. This API recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient. -The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. See [Enable and configure Chat](../get-started/enable). +The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click **Configure** > **Features** > **Message recall**. + +![message-recall](/images/chat/message-recall.png) For each App Key, the call frequency limit of this method is 100 per second. From aa0f5770fff71510b33be17b3bae7561b8fcc88c Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 16 Nov 2023 21:12:18 +0200 Subject: [PATCH 28/37] updates --- .../retrieve-messages/project-implementation/android.mdx | 4 +++- .../retrieve-messages/project-implementation/flutter.mdx | 4 +++- .../messages/retrieve-messages/project-implementation/ios.mdx | 4 +++- .../retrieve-messages/project-implementation/react-native.mdx | 4 +++- .../retrieve-messages/project-implementation/unity.mdx | 4 +++- .../retrieve-messages/project-implementation/windows.mdx | 2 ++ 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index e8175dee2..50e906e11 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -149,9 +149,11 @@ End users can pin up to 50 conversations. After you call this API, the SDK retur Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```java +// limit: The number of sessions returned per page. The value range is [1,50]. +// cursor: The cursor position to start getting data. If `null` or an empty string ("") is passed when obtaining data, the SDK will start querying from the latest pinned session. String cursor = ""; int limit = 40; List conversations = new ArrayList<>(); diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index ee64bfbfb..c30d990ee 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -115,9 +115,11 @@ End users can pin up to 50 conversations. After you call this API, the SDK retur Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```dart +// pageSize: The number of sessions returned per page. The value range is [1,50]. +// cursor: The cursor position to start getting data. If `null` or an empty string ("") is passed when obtaining data, the SDK will start querying from the latest pinned session. String? cursor; int pageSize = 10; ChatCursorResult result = diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index b24840c1f..4de2f5f36 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -73,9 +73,11 @@ End users can pin up to 50 conversations. After you call this API, the SDK retur Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```objc +// pageSize: Number of sessions returned per page. The value range is [1,50]. +// cursor: The starting position of the query. If `nil` or `@""` is passed in, the SDK will start querying from the latest pinned session. [AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { }]; diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index fdc2a75c3..767843e04 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -102,9 +102,11 @@ End users can pin up to 50 conversations. After you call this API, the SDK retur Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```typescript +// pageSize: The number of sessions returned per page. The value range is [1,50]。 +// cursor:The cursor position to start getting data. ChatClient.getInstance() .chatManager.fetchPinnedConversationsFromServerWithCursor(cursor, pageSize) .then(() => { diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index 5504a117e..8485c1aa7 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -118,9 +118,11 @@ End users can pin up to 50 conversations. After you call this API, the SDK retur Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation. -The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: +Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp +// limit: The number of sessions returned per page. The value range is [1,50]. +// cursor: The cursor position to start getting data. int limit = 10; string cursor = ""; bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index bf4d58faf..62666f00c 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -117,6 +117,8 @@ Agora Chat servers store a list of conversations that remain active in the past The Limit parameter specifies the number of conversations each API call can return, from a range of 1-50. Refer to the following code example to get a list of pinned conversations from the server with pagination: ```csharp +// limit: The number of sessions returned per page. The value range is [1,50]. +// cursor: The cursor position to start getting data. int limit = 10; string cursor = ""; bool pinOnly = true; // `false`: Get the list of all conversations; `true`: Get the list of only pinned conversations. From 40f63e2721a0657568e7540a32fda26b31ee5189 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Thu, 16 Nov 2023 21:29:06 +0200 Subject: [PATCH 29/37] review updates --- .../restful-api/_user-system-registration.mdx | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/shared/chat-sdk/restful-api/_user-system-registration.mdx b/shared/chat-sdk/restful-api/_user-system-registration.mdx index e4b96f7f0..56145ff95 100644 --- a/shared/chat-sdk/restful-api/_user-system-registration.mdx +++ b/shared/chat-sdk/restful-api/_user-system-registration.mdx @@ -52,13 +52,7 @@ The request body is a JSON object, which contains the following fields: #### Response body -If the returned HTTP status code is `200`, the request succeeds, and the response body contains the following fields: - -| Field | Type | Description | -| :------------------ | :----- | :--------------------------------------------------------------------------------------------------------- | -| `entities.nickname` | String | The nickname of the user displayed in the notification bar of the message push when the message is pushed.
    This field is not the user nickname of the user attributes. | - -For other fields and detailed descriptions, see [Common parameters](#param). +If the returned HTTP status code is `200`, the request succeeds. For fields and detailed descriptions, see [Common parameters](#param). If the returned HTTP status code is not `200`, the request fails. You can refer to [Status codes](/agora-chat/reference/http-status-codes) for possible reasons. @@ -131,7 +125,6 @@ The request body is a JSONArray object, which contains the following fields: | :--------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | | `username` | String | The unique login account of the user. The username must be 64 bytes or less and cannot be empty. | Yes | | `password` | String | The user's login password. The length cannot exceed 64 bytes. | Yes | -| `nickname` | String | The nickname of the user displayed in the notification bar of the message push when the message is pushed. The length cannot exceed 100 bytes. The default value is null.
    This field is used to set the user nickname displayed in the message push, not the user nickname in the user attributes. | Yes | ### HTTP response @@ -141,7 +134,6 @@ If the returned HTTP status code is `200`, the request succeeds, and the respons | Field | Type | Description | | :------------------ | :--------- | :------------------------------------------------------------------------------------------- | -| `entities.nickname` | String | The nickname of the user displayed in the notification bar of the message push when the message is pushed.
    This field is not the user nickname of the user attributes. | | `data` | JSONArray | The details of the response. In this `data` array, the username and reason for the registration failure are displayed. | For other fields and detailed descriptions, see [Common parameters](#param). @@ -160,12 +152,10 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA { "username":"user1", "password":"123", - "nickname":"testuser1" }, { "username":"user2", "password":"456", - "nickname":"testuser2" } ]' ``` @@ -186,7 +176,6 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA "modified": 1541587920710, "username": "user1", "activated": true, - "nickname": "testuser1" }, { "uuid": "278bac80-XXXX-XXXX-b192-73e4cd5078a5", @@ -195,7 +184,6 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA "modified": 1541587920712, "username": "user2", "activated": true, - "nickname": "testuser2" } ], "timestamp": 1541587920714, @@ -216,17 +204,14 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA { "username":"user1", "password":"123", - "nickname":"testuser1" }, { "username":"user2", "password":"456", - "nickname":"testuser2" }, { "username":"user3", "password":"789", - "nickname":"testuser3" } ]' ``` @@ -247,7 +232,6 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA "modified": 1541587920710, "username": "user1", "activated": true, - "nickname": "testuser1" }, { "uuid": "278bac80-XXXX-XXXX-b192-73e4cd5078a5", @@ -256,7 +240,6 @@ curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer {YourA "modified": 1541587920712, "username": "user2", "activated": true, - "nickname": "testuser2" } ], "timestamp": 1541587920714, From 60c9921dc5ebdf1a1e537eec489d1aaa639d00a0 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 20 Nov 2023 15:36:08 +0200 Subject: [PATCH 30/37] review comments --- .../retrieve-messages/project-implementation/android.mdx | 4 ++-- .../retrieve-messages/project-implementation/flutter.mdx | 4 ++-- .../messages/retrieve-messages/project-implementation/ios.mdx | 4 ++-- .../retrieve-messages/project-implementation/react-native.mdx | 4 ++-- .../retrieve-messages/project-implementation/unity.mdx | 4 ++-- .../messages/retrieve-messages/project-implementation/web.mdx | 4 ++-- .../retrieve-messages/project-implementation/windows.mdx | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index 50e906e11..c8013bbeb 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -59,8 +59,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index c30d990ee..92916844c 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -39,8 +39,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 4de2f5f36..ca2aa63c4 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -27,8 +27,8 @@ You can set the search direction to retrieve messages in the chronological or re The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 767843e04..00c0e754d 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -28,8 +28,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index 8485c1aa7..a1d57a4b6 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -39,8 +39,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 2d6b60688..046a47c91 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -25,8 +25,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 62666f00c..2424d36b3 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -40,8 +40,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Send 500 offline messages/conversation by default; -- Chat Group: Send 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages/conversation by default; +- Chat Group: Store 200 offline messages/conversation by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. From 0aa3f0f63fcd42b87f39fce2dd768a0d25cb1799 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 20 Nov 2023 22:26:39 +0200 Subject: [PATCH 31/37] review comments --- .../project-implementation/android.mdx | 54 ++++-------- .../project-implementation/flutter.mdx | 56 ++----------- .../project-implementation/ios.mdx | 32 ++----- .../project-implementation/react-native.mdx | 45 +++------- .../project-implementation/unity.mdx | 84 ++++++++----------- .../project-implementation/web.mdx | 34 ++------ .../project-implementation/windows.mdx | 67 ++++++--------- 7 files changed, 109 insertions(+), 263 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index c8013bbeb..b21b7f481 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -2,38 +2,30 @@ ### Retrieve a list of conversations from the server -Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `asyncFetchConversationsFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java -String conversationId=" "; -Conversation.ConversationType type=Conversation.ConversationType.Chat; -FetchMessageOption option=new FetchMessageOption(); -//for example -//option.setIsSave(true); -int pageSize = 40; String cursor = ""; -List messages = new ArrayList<>(); -doAsyncFetchHistoryMessages(conversationId,type,pageSize,cursor,option,messages); +int limit = 40; +List conversations = new ArrayList<>(); +doAsyncFetchConversationsFromServer(limit,cursor,conversations); -private void doAsyncFetchHistoryMessages(String conversationId, - Conversation.ConversationType type, - int pageSize,String cursor, - FetchMessageOption option, - List messages){ - ChatClient.getInstance().chatManager().asyncFetchHistoryMessages(conversationId, type, pageSize, cursor, option, new ValueCallBack>() { +private void doAsyncFetchConversationsFromServer(final int limit, final String cursor,List conversations){ + ChatClient.getInstance().chatManager().asyncFetchConversationsFromServer(limit, cursor, new ValueCallBack>() { @Override - public void onSuccess(CursorResult value) { + public void onSuccess(CursorResult value) { if (value != null ) { - List list = value.getData(); + List list = value.getData(); if (list != null && list.size() > 0) { - messages.addAll(list); + conversations.addAll(list); } String newCursor = value.getCursor(); if( !TextUtils.isEmpty(newCursor)) { - doAsyncFetchHistoryMessages(conversationId, type, pageSize, newCursor, option, messages); + doAsyncFetchConversationsFromServer(limit, newCursor, conversations); } } + } @Override @@ -49,11 +41,9 @@ If you still use the `asyncFetchConversationsFromServer` method to retrieve the ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can use these methods to retrieve historical messages from the server: - - By pagination - - For a time range +After retrieving conversations, you can retrieve historical messages from the server. -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -67,23 +57,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```java -ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(conversationId, conversationType, pageSize, startMsgId, new ValueCallBack>() { - @Override - public void onSuccess(CursorResult value) { - - } - @Override - public void onError(int error, String errorMsg) { - } - }); -``` - -#### Retrieve historical messages for a time range - -Using `FetchMessageOption` to configure the time range parameters, the `asyncFetchHistoryMessages` method can retrieve historical messages of a conversation from the server for a specific range of time. +Refer to the following code sample: ```java String conversationId=" "; diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index 92916844c..bc0b20123 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -2,38 +2,26 @@ ### Retrieve a list of conversations from the server -Call `fetchConversationListFromServer` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. +Call `fetchConversation` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `loadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```dart -ChatConversationType conversationType = ChatConversationType.Chat; -FetchMessageOptions options = FetchMessageOptions( - from: senderId, - direction: ChatSearchDirection.Up, - startTs: 1695720454000, - endTs: 1695720554000, - needSave: false, -); - -ChatCursorResult result = - await ChatClient.getInstance.chatManager.fetchHistoryMessagesByOption( - conversationId, - conversationType, - options: options, +String? cursor; +int pageSize = 10; +ChatCursorResult result = + await ChatClient.getInstance.chatManager.fetchConversation( cursor: cursor, pageSize: pageSize, ); ``` -For users that do not support `fetchConversationListFromServer`, call `getConversationsFromServer` to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). +For users that do not support `fetchConversation`, call `getConversationsFromServer` to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can use these methods to retrieve historical messages from the server: - - By pagination - - For a time range +After retrieving conversations, you can retrieve historical messages from the server. -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -47,32 +35,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```dart -try { - // The conversation ID. - String convId = "convId"; - // The conversation type. - ChatConversationType convType = ChatConversationType.Chat; - // The maximin number of messages - int pageSize = 10; - // The message ID from which to start retrieving - String startMsgId = ""; - ChatCursorResult cursor = - await ChatClient.getInstance.chatManager.fetchHistoryMessages( - conversationId: convId, - type: convType, - pageSize: pageSize, - startMsgId: startMsgId, - ); -} on ChatError catch (e) { -} -``` - -#### Retrieve historical messages for a time range - -Using `FetchMessageOptions` to configure the time range parameters, the `fetchHistoryMessagesByOption` method can retrieve historical messages of a conversation from the server for a specific range of time. +Refer to the following code sample: ```dart ChatConversationType conversationType = ChatConversationType.Chat; @@ -92,7 +55,6 @@ ChatCursorResult result = cursor: cursor, pageSize: pageSize, ); - ``` ### Pin a conversation diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index ca2aa63c4..2c0294df3 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -2,29 +2,25 @@ ### Retrieve a list of conversations from the server -Call `getConversationsFromServerByPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `getConversationsFromServerWithCursor:pageSize:completion` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```objective-c -AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOption alloc] init]; - [AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) { +[AgoraChatClient.sharedClient.chatManager getConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) { - }]; +}]; ``` -For users that do not support `getConversationsFromServerByPage`, call `getConversationsFromServer` method to retrieve the conversations from the server, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). +For users that do not support `getConversationsFromServerWithCursor:pageSize:completion`, call `getConversationsFromServer` method to retrieve the conversations from the server, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can use these methods to retrieve historical messages from the server: +After retrieving conversations, you can retrieve historical messages from the server. - - By pagination - - For a time range +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. - The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: - 1:1 private chat: Store 500 offline messages/conversation by default; @@ -35,23 +31,13 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```objective-c -[[AgoraChatClient sharedClient].chatManager asyncFetchHistoryMessagesFromServer:conversation.conversationId conversationType:conversation.type startMessageId:@"startMsgId" pageSize:10 completion:^(AgoraChatCursorResult * _Nullable aResult, AgoraChatError * _Nullable aError) { - [conversation loadMessagesStartFromId:@"startMsgId" count:10 searchDirection:AgoraChatMessageSearchDirectionUp completion:nil]; - }]; -``` - -#### Retrieve historical messages for a time range - -Using `AgoraChatFetchServerMessagesOption` to configure the time range parameters, the `fetchMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. +Refer to the following code sample: ```objective-c AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOption alloc] init]; -[AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) { + [AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) { -}]; + }]; ``` ### Pin a conversation diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 00c0e754d..1d61f1eb8 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -2,19 +2,18 @@ ### Retrieve a list of conversations from the server -Call `fetchConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. +Call `fetchConversationsFromServerWithCursor` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `getAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```java -// pageNum: The current page number, starting from 1. -// pageSize: The number of conversations to get per page. The value range is [1,20]. +// cursor: If `cursor` is an empty string, the SDK retrieves from the latest conversation. ChatClient.getInstance() - .chatManager.fetchConversationsFromServerWithPage(pageSize, pageNum) - .then((result) => { - console.log("test:success:", result); + .chatManager.fetchConversationsFromServerWithCursor(cursor, pageSize) + .then(() => { + console.log("get conversions success"); }) - .catch((error) => { - console.warn("test:error:", error); + .catch((reason) => { + console.log("get conversions fail.", reason); }); ``` @@ -22,7 +21,9 @@ For users that do not support `fetchConversationsFromServerWithPage`, call `fetc ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +After retrieving conversations, you can retrieve historical messages from the server. + +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -36,31 +37,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```typescript -// Specify the conversation ID. -const convId = "convId"; -// Specify the conversation type. For details, see descriptions in ChatConversationType. -const convType = ChatConversationType.PeerChat; -// Specify the maximum count of the retrieved messages. -const pageSize = 10; -// Specify the message ID from which to retrieve the historical messages. -const startMsgId = ""; -// Specify the message search direction. -const direction = ChatSearchDirection.UP; -ChatClient.getInstance() - .chatManager.fetchHistoryMessages(convId, chatType, { - pageSize, - startMsgId, - direction, - }) - .then((messages) => { - console.log("get message success: ", messages); - }) -``` - -#### Retrieve historical messages for a time range +Refer to the following code sample: ```typescript ChatClient.getInstance() diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index a1d57a4b6..5cc630b4b 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -2,38 +2,42 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +Call `GetConversationsFromServerWithCursor` to retrieve conversations from the server with pagination. You can set the `pinOnly` parameter in this method to determine whether to retrieve the list of pinned conversations: +- If `pinOnly` is set to `false`, you can retrieve the list of pinned and unpinned conversations. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). +- If pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. + +In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp -FetchServerMessagesOption option = new FetchServerMessagesOption(); - option.IsSave = false; - option.Direction = MessageSearchDirection.UP; - option.From = "user"; - option.MsgTypes = new List(); - option.MsgTypes.Add(MessageBodyType.TXT); - option.MsgTypes.Add(MessageBodyTypeTime = 1695720454000; - option.EndTime = 1695720554000; - - SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( - onSuccess: (result) = > - { - } , - onError: (code, desc) = > - { - } - ) ) ; +int limit = 10; +string cursor = ""; +bool pinOnly = false; // `false`:Get the list of all conversations; `true`: Get the list of only pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next request + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); ``` For users that do not support `GetConversationsFromServerWithPage`, call `GetConversationsFromServer` to retrieve all the conversations from the server. By default, the SDK retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can use these methods to retrieve historical messages from the server: - - By pagination - - For a time range +After retrieving conversations, you can retrieve historical messages from the server. -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -47,27 +51,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```csharp -SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, type, startId, pageSize, new ValueCallBack>( - // Fetching historical messages succeeds. - // `result` is in the format of CursorResult. - onSuccess: (result) => { - }, - // Fetching historical messages fails. - onError:(code, desc) => { - } -)); -``` - -#### Retrieve historical messages for a time range - -Using `FetchServerMessagesOption` to configure the time range parameters, the `FetchHistoryMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. - -If you have implemented Chat SDK after June 8, 2023, you can call the same client API to take use of this feature. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. - -The Agora Chat server stores up to 200 messages per chat group. You can store extra messages on your app server by using a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. +Refer to the following code sample: ```csharp FetchServerMessagesOption option = new FetchServerMessagesOption(); @@ -81,15 +65,15 @@ option.StartTime = 1695720454000; option.EndTime = 1695720554000; SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( - onSuccess: (result) => - { - }, - onError: (code, desc) => - { + onSuccess: (result) => + { + }, + onError: (code, desc) => - } -)); + { + } + )) ; ``` ### Pin a conversation diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 046a47c91..f9b2addf9 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -2,7 +2,7 @@ ### Retrieve a list of conversations from the server -Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. +Call `getServerConversations` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user.
    Do not use mixed upper-case.
    @@ -12,14 +12,15 @@ Call `getServerConversations` to retrieve conversations from the server with pag connection.getServerConversations({pageSize:50, cursor: ''}).then((res)=>{ console.log(res) }) - ``` If you still use the `getConversationlist` method to retrieve the conversations from the server without pagination, the SDK, by default, retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can retrieve historical messages by pagination from the server. You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +After retrieving conversations, you can retrieve historical messages from the server. + +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -33,32 +34,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```javascript -var options = { - // The ID of the peer user, or chat group, or chat room, depending on the chat type. - targetId:'user1', - // (Optional) The number of messages that you expect to get on each page. The value range is [1,50] and the default value is 20. - pageSize: 20, - // (Optional) The starting message ID for query. If the parameter is set as -1, an empty string, or null, the SDK retrieves messages from the latest one. - cursor: -1, - // (Optional) The conversation type. (Default) singleChat: one-to-one conversation; groupChat: group conversation; chatRoom: chat room conversation. - chatType:'groupChat', - // The message search direction. - // (Default) up: Messages are retrieved in the reverse chronological order of when the server receives them; - // down: Messages are retrieved in the chronological order of when the server receives them. - searchDirection: 'up', -} -WebIM.conn.getHistoryMessages(options).then((res)=>{ - // Occurs when historical messages are successfully retrieved. - console.log(res) -}).catch((e)=>{ - // Occurs when historical messages fail to be retrieved. -}) -``` - -#### Retrieve historical messages by time range +Refer to the following code sample: ```javascript connection.getHistoryMessages({ diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 2424d36b3..a6b2dd862 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -2,39 +2,42 @@ ### Retrieve a list of conversations from the server -Call `GetConversationsFromServerWithPage` to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). Each retrieved conversation contains one last historical message. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. +Call `GetConversationsFromServerWithCursor` to retrieve conversations from the server with pagination. You can set the `pinOnly` parameter in this method to determine whether to retrieve the list of pinned conversations: +- If `pinOnly` is set to `false`, you can retrieve the list of pinned and unpinned conversations. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). +- If pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. + +In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. ```csharp -FetchServerMessagesOption option = new FetchServerMessageOption(); - option.IsSave = false; - option.Direction = MessageSearchDirection.UP; - option.From = "user"; - option.MsgTypes = new List(); - option.MsgTypes.Add(MessageBodyType.TXT); - option.MsgTypes.Add(MessageBodyType.VIDEO); - option.StartTime = 1695720454000; - option.EndTime = 1695720554000; - - SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServerBy(conversationId, type, cursor, pageSize, option, new ValueCallBack>( - onSuccess: (result) = > - { - }, - onError: (code, desc) = > - { - } - ) ) ; +int limit = 10; +string cursor = ""; +bool pinOnly = false; // `false`:Get all conversations; `true`: Get the list of pinned conversations. +SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cursor, limit, new ValueCallBack>( + onSuccess: (result) => + { + // Traverse the obtained conversation list + foreach (var conv in result.Data) + { + + } + // The cursor for the next request + string nextCursor = result.Cursor; + }, + onError: (code, desc) => + { + + } +)); ``` For users that do not support `GetConversationsFromServerWithPage`, call `GetConversationsFromServer` to retrieve all the conversations from the server. By default, the SDK retrieves the last ten conversations in the past seven days, and each conversation contains one last historical message. To adjust the time limit or the number of conversations retrieved, contact [support@agora.io](mailto:support@agora.io). ### Retrieve historical messages of the specified conversation -After retrieving conversations, you can use these methods to retrieve historical messages from the server: - - By pagination - - For a time range +After retrieving conversations, you can retrieve historical messages from the server. -You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them. +You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database. If you have implemented Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact [support@agora.io](mailto:support@agora.io) to enable this. @@ -48,23 +51,7 @@ For users to receive more offline messages, use the client API or a webhook to s To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database. -#### Retrieve historical messages by pagination - -```csharp -SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(conversationId, type, startId, pageSize, new ValueCallBack>( - // Fetching historical messages succeeds. - // `result` is in the format of CursorResult. - onSuccess: (result) => { - }, - // Fetching historical messages fails. - onError:(code, desc) => { - } -)); -``` - -#### Retrieve historical messages for a time range - -Using `FetchServerMessagesOption` to configure the time range parameters, the `FetchHistoryMessagesFromServerBy` method can retrieve historical messages of a conversation from the server for a specific range of time. +Refer to the following code sample: ```csharp FetchServerMessagesOption option = new FetchServerMessagesOption(); From 8e0bf3d3b5051c334a5db60493b3b9d88195984f Mon Sep 17 00:00:00 2001 From: atovpeko Date: Wed, 22 Nov 2023 22:05:22 +0200 Subject: [PATCH 32/37] review comments --- .../client-api/messages/_send-receive-messages.mdx | 2 +- .../retrieve-messages/project-implementation/unity.mdx | 2 +- .../retrieve-messages/project-implementation/windows.mdx | 2 +- .../project-implementation/android.mdx | 2 +- .../project-implementation/flutter.mdx | 2 +- .../send-receive-messages/project-implementation/ios.mdx | 2 +- .../project-implementation/react-native.mdx | 2 +- .../project-implementation/unity.mdx | 2 +- .../send-receive-messages/project-implementation/web.mdx | 2 +- .../project-implementation/windows.mdx | 2 +- shared/chat-sdk/develop/_content-moderation.mdx | 2 +- shared/chat-sdk/reference/_limitations.mdx | 8 ++++---- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx index 7691b5554..91f859572 100644 --- a/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx +++ b/shared/chat-sdk/client-api/messages/_send-receive-messages.mdx @@ -17,7 +17,7 @@ The Chat message feature is language agnostic. End users can send messages in an In addition to sending messages, users can also forward one or more messages. When forwarding multiple messages, users have the following options: * Forward messages one-by-one -* Forward consolidated messages as message history +* Forward combined messages as message history This page shows how to implement sending, receiving, forwarding multiple messages, and modifying sent messages using the . diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index 5cc630b4b..bf1e0c34f 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -4,7 +4,7 @@ Call `GetConversationsFromServerWithCursor` to retrieve conversations from the server with pagination. You can set the `pinOnly` parameter in this method to determine whether to retrieve the list of pinned conversations: - If `pinOnly` is set to `false`, you can retrieve the list of pinned and unpinned conversations. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). -- If pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. +- If `pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index a6b2dd862..41a9d8f14 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -4,7 +4,7 @@ Call `GetConversationsFromServerWithCursor` to retrieve conversations from the server with pagination. You can set the `pinOnly` parameter in this method to determine whether to retrieve the list of pinned conversations: - If `pinOnly` is set to `false`, you can retrieve the list of pinned and unpinned conversations. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). -- If pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. +- If `pinOnly` is set to `true`, you can only retrieve the list of pinned conversations. The SDK returns the pinned conversations in the reverse chronological order of when they were pinned. Up to 50 pinned conversations can be retrieved. In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call `LoadAllConversations` to retrieve conversations on the local device. The server stores 100 conversations for 7 days by default. To increase the two upper limits, contact support@agora.io. Agora Chat server can store up to 3,000 conversation per end user. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 04e8cafaa..91a9e9502 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -342,7 +342,7 @@ message.getStringAttribute("attribute1",null);message.getBooleanAttribute("attri ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index 70dd57fa3..b1819ba24 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -280,7 +280,7 @@ ChatClient.getInstance.chatManager.addEventHandler( ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 1ecaad913..2c800d832 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -362,7 +362,7 @@ message.chatType = AgoraChatTypeChat; ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index d87a124b2..efd30c982 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -210,7 +210,7 @@ onMessagesRecalled(messages: ChatMessage[]): void; ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index 32601d84a..b6633132e 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -404,7 +404,7 @@ if (found) { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 129db8e8f..9f37c8b87 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -506,7 +506,7 @@ function sendPrivateText() { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: 1. Create a combined message using multiple message IDs: diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index bfce1f009..bc63ea80d 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -404,7 +404,7 @@ if (found) { ### Forward multiple messages -Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a consolidated message with a list of original messages and send it. When receiving a consolidated message, the recipient can select it and other messages to create a new layered consolidated message. A consolidated message can contain up to 10 layers of messages, with at most 300 messages at each layer. +Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer. To forward and receive combined messages, refer to the following code: diff --git a/shared/chat-sdk/develop/_content-moderation.mdx b/shared/chat-sdk/develop/_content-moderation.mdx index bb05b7e7c..08f6abc9c 100644 --- a/shared/chat-sdk/develop/_content-moderation.mdx +++ b/shared/chat-sdk/develop/_content-moderation.mdx @@ -64,7 +64,7 @@ After enabling the text and image moderation feature on Agora Console, you can s You can also impose a penalty on users who reach the violation limit within a time period. The moderation penalties include the following: - Penalties at the app level or in one-to-one chat: - - **Ban**: If the user is banned, he will be forced to go offline immediately and cannot log in to Agora Chat. The banned user cannot log in again until he or she is unbanned. For example, if a user sends inappropriate content 5 times within 1 minute, he or she will be banned. Once a user is banned, the user state is changed to `Blocked` on the **Users** page under **Operation Management**. You can click **Unblock** in the **Action** column or call the [RESTful API](user-system-registration#Unbanning-a-user) to unblock the user。 + - **Ban**: If the user is banned, he will be forced to go offline immediately and cannot log in to Agora Chat. The banned user cannot log in again until he or she is unbanned. For example, if a user sends inappropriate content 5 times within 1 minute, he or she will be banned. Once a user is banned, the user state is changed to `Blocked` on the **Users** page under **Operation Management**. You can click **Unblock** in the **Action** column or call the [RESTful API](../restful-api/user-system-registration#unbanning-a-user) to unblock the user. - **Force Offline**: The user is forced to go offline and needs to log in again to use Agora Chat normally. - **Delete**: The user is removed. If the user is the group owner or chat room owner, the system will delete the corresponding group and chat room at the same time. diff --git a/shared/chat-sdk/reference/_limitations.mdx b/shared/chat-sdk/reference/_limitations.mdx index 064f45c2c..ba4c81b98 100644 --- a/shared/chat-sdk/reference/_limitations.mdx +++ b/shared/chat-sdk/reference/_limitations.mdx @@ -11,10 +11,10 @@ The length limits of the different types of messages are as follows: | **Message type** | **Length limit** | **Related API** | | --- | --- | --- | | Text message | 5 KB | createTxtSendMessage | -| Image message | 10 MB |
    • createImageSendMessage[1/2]
    • createImageSendMessage[2/2]
    | +| Image message | 10 MB |
    • createImageSendMessage[1/2]
    • createImageSendMessage[2/2]
    | | Voice message | 10 MB |
    • createVoiceSendMessage[1/2]
    • createVoiceSendMessage[2/2]
    | -| Video message | 10 MB |
    • createVideoSendMessage[1/3]
    • createVideoSendMessage[2/3]
    • createVideoSendMessage[3/3]
    | -| File message | 10 MB |
    • createFileSendMessage[1/2]
    • createFileSendMessage
    | +| Video message | 10 MB |
    • createVideoSendMessage[1/3]
    • createVideoSendMessage[2/3]
    • createVideoSendMessage[3/3]
    | +| File message | 10 MB |
    • createFileSendMessage[1/2]
    • createFileSendMessage[2/2]
    | | Transparent transmission message | 5 KB | createSendMessage | | Customized extended message | The size of the extended message must not exceed that of the original message. | createSendMessage | | Customized message | 5 KB | createSendMessage | @@ -62,7 +62,7 @@ Each chat room can have up to 100 custom attributes, and the total size of chat * The forwarding multiple messages​ capability is available only in client APIs and not RESTful APIs. * End users can only forward up to 300 messages at a time. * The content of the forwarded messages can't be searched. -* When forwarding multiple messages in a consolidated form, the title and preview of the combined message is displayed. The content of the message preview can't exceed 5KB. +* When forwarding multiple messages in a combined form, the title and preview of the combined message is displayed. The content of the message preview can't exceed 5KB. * Applications developed with versions prior to `1.2.x` will not support display of forwarded messages. ### Sent message modification limitations From c2bb98e1ba6c1151bd592b1a7f0bb6f9b069dc99 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 27 Nov 2023 12:45:00 +0200 Subject: [PATCH 33/37] Review comments --- .../manage-messages/project-implementation/android.mdx | 4 ++-- .../messages/manage-messages/understand/android.mdx | 2 +- .../retrieve-messages/project-implementation/web.mdx | 6 +++--- .../messages/retrieve-messages/understand/android.mdx | 3 ++- .../messages/retrieve-messages/understand/flutter.mdx | 3 ++- .../messages/retrieve-messages/understand/ios.mdx | 3 ++- .../messages/retrieve-messages/understand/react-native.mdx | 4 +++- .../messages/retrieve-messages/understand/unity.mdx | 3 ++- .../messages/retrieve-messages/understand/web.mdx | 2 ++ .../messages/retrieve-messages/understand/windows.mdx | 3 ++- 10 files changed, 21 insertions(+), 12 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx index e04ea9800..51e9b9f45 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/project-implementation/android.mdx @@ -2,10 +2,10 @@ ### Retrieve conversations -Call `loadAllConversations` to retrieve all the conversations on the local device: +You can call the `getAllConversationsBySort` method to get all local conversations. The SDK first retrieves the conversations from the memory. If no conversation is loaded from the local database, the SDK will load the conversations to the memory. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation), with the pinned conversations coming before the unpinned ones. The conversation list is of the `List` structure: ```java -Map conversations = ChatClient.getInstance().chatManager().getAllConversations(); +List conversations = ChatClient.getInstance().chatManager().getAllConversationsBySort(); ``` ### Retrieve messages in the specified conversation diff --git a/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx b/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx index acc368082..33e3b5f56 100644 --- a/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx +++ b/shared/chat-sdk/client-api/messages/manage-messages/understand/android.mdx @@ -2,7 +2,7 @@ SQLCipher is used to encrypt the database that stores local messages. The Chat SDK uses `ChatManager` to manage local messages. Followings are the core methods: -- `loadAllConversations`: Loads the conversation list on the local device. +- `getAllConversationsBySort`: Loads the conversation list on the local device. - `deleteConversation`: Deletes the specified conversation locally. - `deleteConversationFromServer`: Delete a conversation from the server. - `Conversation.getUnreadMsgCount`: Retrieves the count of unread messages in the specified conversation. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index f9b2addf9..2679c8473 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -6,7 +6,7 @@ Call `getServerConversations` to retrieve conversations from the server with pag
    Do not use mixed upper-case.
    -```javaScript +```javascript // pageSize: The number of conversations that you expect to get on each page. The value range is [1,50] and the default value is `20`. // cursor: The cursor position for starting to get data. If you pass in an empty string (''), the SDK retrieves conversations from the latest active one. connection.getServerConversations({pageSize:50, cursor: ''}).then((res)=>{ @@ -55,7 +55,7 @@ connection.getHistoryMessages({ Refer to the following code example to pin a conversation: -```javaScript +```javascript connection.pinConversation({conversationId:'conversationId', conversationType: 'singleChat', isPinned: true}) ``` @@ -67,7 +67,7 @@ Agora Chat servers store a list of conversations that remain active in the past Refer to the following code example to get a list of pinned conversations from the server with pagination: -```javaScript +```javascript // pageSize: The number of sessions returned per page. The value range is [1,50]。 // cursor:The cursor position to start getting data. If an empty string ('') is passed, the SDK will start querying from the latest pinned session. connection.getServerPinnedConversations({pageSize:50, cursor: ''}) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx index ba90f0a5d..66a85764a 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/android.mdx @@ -3,8 +3,9 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. The followings are the core methods: - `asyncFetchConversationsFromServer`: Retrieves a list of conversations stored on the server. -- `asyncFetchHistoryMessage`: Retrieves the historical messages in the specified conversation from the server. - `asyncFetchHistoryMessages`: Retrieves historical messages of a conversation from the server according to `FetchMessageOption`, the parameter configuration class for retrieving historical messages. +- `asyncPinConversation`: Pins conversations. +- `asyncFetchPinnedConversationsFromServer`: Retrieves pinned conversations. - `removeMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `deleteConversationFromServer`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx index 0a3e7dee3..a9a310552 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/flutter.mdx @@ -3,8 +3,9 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. The following are the core methods: - `fetchConversationListFromServer`: Retrieves a list of conversations stored on the server. -- `fetchHistoryMessages`: Retrieves the historical messages in the specified conversation from the server. - `fetchHistoryMessagesByOption`: Retrieves historical messages of a conversation from the server according to `FetchMessageOptions`, the parameter configuration class for retrieving historical messages. +- `pinConversation`: Pins a conversation. +- `fetchPinnedConversations`: Retrieves a list of pinned conversations. - `deleteRemoteMessagesBefore`/`deleteRemoteMessagesWithIds`: Deletes historical messages from the server unidirectionally. - `deleteRemoteConversation`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx index 2010c5c29..61c03ab30 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/ios.mdx @@ -3,8 +3,9 @@ The Chat SDK uses `IAgoraChatManager` to retrieve historical messages from the server. The following are the core methods: - `getConversationsFromServer`: Retrieves a list of conversations stored on the server. -- `asyncFetchHistoryMessagesFromServer`: Retrieves the historical messages in the specified conversation from the server. - `fetchMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `AgoraChatFetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. +- `pinConversation`: Pins a conversation. +- `getPinnedConversationsFromServerWithCursor`: Retrieves a list of pinned conversations. - `removeMessagesFromServerWithTimeStamp`/`removeMessagesFromServerMessageIds`: Deletes historical messages from the server unidirectionally. - `deleteServerConversation`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/react-native.mdx index 287e32f9e..b8af121fa 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/react-native.mdx @@ -3,7 +3,9 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. The following are the core methods: - `fetchAllConversations`: Retrieves a list of conversations stored on the server. -- `fetchHistoryMessages`: Retrieves the historical messages in the specified conversation from the server. +- `fetchHistoryMessagesByOptions`: Retrieves historical messages of a conversation from the server according to `ChatFetchMessageOptions`, the parameter configuration class for retrieving historical messages. +- `pinConversation`: Pins a conversation. +- `fetchPinnedConversationsFromServerWithCursor`: Retrieves a list of pinned conversations. - `removeMessagesFromServerWithTimestamp`/`removeMessagesFromServerWithMsgIds`: Deletes historical messages from the server unidirectionally. - `removeConversationFromServer`: Deletes conversations and related messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx index c9c2409a5..619949e55 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/unity.mdx @@ -3,8 +3,9 @@ The Chat SDK uses `IChatManager` to retrieve historical messages from the server. The following are the core methods: - `GetConversationsFromServerWithPage`: Retrieve conversations stored on the server with pagination. -- `FetchHistoryMessagesFromServer`: Retrieve the historical messages in the specified conversation from the server. - `FetchHistoryMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. +- `PinConversation`: Pins a conversation. +- `GetConversationsFromServerWithCursor`: Retrieves a list of pinned conversations. - `RemoveMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `DeleteConversationFromServer`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx index 32abaced1..9452f4758 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/web.mdx @@ -4,6 +4,8 @@ The Chat SDK uses `ChatManager` to retrieve historical messages from the server. - `getServerConversations`: Retrieves a list of conversations stored on the server with pagination. - `getHistoryMessages`: Retrieves the historical messages in the specified conversation from the server. +- `pinConversation`: Pin a conversation. +- `getServerPinnedConversations`: Retrieves a list of pinned conversations. - `removeHistoryMessages`: Deletes historical messages from the server unidirectionally. - `deleteConversation`: Deletes conversations and their historical messages from the server. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx index dc9e665a8..fbf837041 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/understand/windows.mdx @@ -3,8 +3,9 @@ The Chat SDK uses `IChatManager` to retrieve historical messages from the server. The following are the core methods: - `GetConversationsFromServerWithPage`: Retrieve conversations stored on the server with pagination. -- `FetchHistoryMessagesFromServer`: Retrieve the historical messages in the specified conversation from the server. - `FetchHistoryMessagesFromServerBy`: Retrieves historical messages of a conversation from the server according to `FetchServerMessagesOption`, the parameter configuration class for retrieving historical messages. +- `PinConversation`: Pins a conversation. +- `GetConversationsFromServerWithCursor`: Retrieves a list of pinned conversations. - `RemoveMessagesFromServer`: Deletes historical messages from the server unidirectionally. - `DeleteConversationFromServer`: Deletes conversations and their historical messages from the server. From 0d3b7912a0c5f787d80ef0ff6d65570dbe7ec609 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Mon, 4 Dec 2023 15:00:50 +0200 Subject: [PATCH 34/37] Setenabled/setmuted difference --- shared/video-sdk/develop/_product-workflow.mdx | 1 - .../develop/product-workflow/reference/web.mdx | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/shared/video-sdk/develop/_product-workflow.mdx b/shared/video-sdk/develop/_product-workflow.mdx index b58bc53c9..19c6449db 100644 --- a/shared/video-sdk/develop/_product-workflow.mdx +++ b/shared/video-sdk/develop/_product-workflow.mdx @@ -11,7 +11,6 @@ To use for audio and video communication, you implement a simple The basics of joining and leaving a channel are presented in the project for . This document explains the common workflows you need to handle in your app. - ## Understand the tech The following figure shows the typical workflow you integrate into your in order to publish and subscribe to audio and video streams. diff --git a/shared/video-sdk/develop/product-workflow/reference/web.mdx b/shared/video-sdk/develop/product-workflow/reference/web.mdx index 6b5e3b0ca..af533fdb7 100644 --- a/shared/video-sdk/develop/product-workflow/reference/web.mdx +++ b/shared/video-sdk/develop/product-workflow/reference/web.mdx @@ -11,4 +11,16 @@ * IMicrophoneAudioTrack.setDevice * ICameraVideoTrack.setDevice +### setEnabled and setMuted + +Both Web SDK 4.x and 3.x provide APIs for controlling the collection and sending of local audio and video. The differences between these APIs are detailed in the table below. +You cannot call `setEnabled` and `setMuted` at the same time. + + +| API | Capture | Send | Recovery time | +|-----|------------|------|---------------| +| (3.x) Mute-related methods: `Stream.muteAudio` `Stream.unmuteAudio` `Stream.muteVideo` `Stream.unmuteVideo` | After muting, the SDK does not stop audio and video capture. The camera's light does not turn off. | The SDK sends a black frame after muting video and a mute packet after muting audio. Muted users are counted as streaming users, and up to 17 users can stream at the same time in a single channel. | Unmuting after a mute is relatively faster. | +| (4.x)`LocalTrack.setEnabled` | After calling `setEnabled` to disable the track, the SDK stops audio and video capture. The camera's light turns off. | The SDK does not send any data after calling `setEnabled` to disable the track. Users whose tracks are disabled are not counted as streaming users. | Enabling audio and video after disabling it is relatively slower. | +| (4.x)`LocalTrack.setMuted` | After calling `setMuted` to mute the track, the SDK does not stop audio and video capture. The camera's light does not turn off. | The SDK does not send any data after calling `setMuted` to mute the track. Muted users are not counted as streaming users. | Unmuting after a mute is relatively faster. | + From 945036a5060bf10bd22c0ee66103c81f187e5c14 Mon Sep 17 00:00:00 2001 From: Kishan Dhakan Date: Tue, 5 Dec 2023 15:02:24 +0530 Subject: [PATCH 35/37] fix build issues --- shared/chat-sdk/restful-api/_message-management.mdx | 4 ++-- shared/chat-sdk/restful-api/_push-notification-management.mdx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/chat-sdk/restful-api/_message-management.mdx b/shared/chat-sdk/restful-api/_message-management.mdx index b9188353b..6c755f3b5 100644 --- a/shared/chat-sdk/restful-api/_message-management.mdx +++ b/shared/chat-sdk/restful-api/_message-management.mdx @@ -915,7 +915,7 @@ This method enables you to upload images, audios, videos, or other types of file ≤10 MBThe size of the thumbnail remains the same as that of the original file. - >10 MBA thumbnail is generated based on the specified thumbnail-height and thumbnail-width parameters. + 10 MBA thumbnail is generated based on the specified thumbnail-height and thumbnail-width parameters. If you leave thumbnail-height and thumbnail-width empty, the height and width of the thumbnail is 170 × 170 pixels by default. @@ -1841,4 +1841,4 @@ If the request fails, refer to [Status codes](/agora-chat/reference/http-status- ## Status codes -For details, see [HTTP Status Codes](/agora-chat/reference/http-status-codes). \ No newline at end of file +For details, see [HTTP Status Codes](/agora-chat/reference/http-status-codes). diff --git a/shared/chat-sdk/restful-api/_push-notification-management.mdx b/shared/chat-sdk/restful-api/_push-notification-management.mdx index 91e65c0b0..f4f2f492a 100644 --- a/shared/chat-sdk/restful-api/_push-notification-management.mdx +++ b/shared/chat-sdk/restful-api/_push-notification-management.mdx @@ -61,7 +61,7 @@ For the descriptions of other path parameters, see [Common parameters](#param). | Parameter | Type | Description | Required | | :-------------- | :----- | :----------------------------------------------------------- | :------- | | `Content-Type` | String | The content type. Set it as application/json. | Yes | -| `Authorization` | String | The authentication token of the user or administrator, in the format of Bearer ${YourAppToken}, where Bearer is a fixed character, followed by an English space, and then the obtained token value. | Yes | +| `Authorization` | String | The authentication token of the user or administrator, in the format of Bearer `${YourAppToken}`, where Bearer is a fixed character, followed by an English space, and then the obtained token value. | Yes | #### Request body From 91ea93acdcc6c5b48520995401ed1d7f977c06ac Mon Sep 17 00:00:00 2001 From: atovpeko Date: Tue, 5 Dec 2023 14:16:37 +0200 Subject: [PATCH 36/37] Review comments --- .../retrieve-messages/project-implementation/android.mdx | 4 ++-- .../retrieve-messages/project-implementation/flutter.mdx | 4 ++-- .../retrieve-messages/project-implementation/ios.mdx | 4 ++-- .../project-implementation/react-native.mdx | 4 ++-- .../retrieve-messages/project-implementation/unity.mdx | 4 ++-- .../retrieve-messages/project-implementation/web.mdx | 4 ++-- .../retrieve-messages/project-implementation/windows.mdx | 4 ++-- .../project-implementation/android.mdx | 8 +------- .../project-implementation/flutter.mdx | 8 +------- .../send-receive-messages/project-implementation/ios.mdx | 8 +------- .../project-implementation/react-native.mdx | 8 +------- .../project-implementation/unity.mdx | 8 +------- .../send-receive-messages/project-implementation/web.mdx | 8 +------- .../project-implementation/windows.mdx | 8 +------- 14 files changed, 21 insertions(+), 63 deletions(-) diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx index b21b7f481..3e6a8096d 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/android.mdx @@ -49,8 +49,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx index bc0b20123..8cd271aef 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/flutter.mdx @@ -27,8 +27,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx index 2c0294df3..598007472 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/ios.mdx @@ -23,8 +23,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx index 1d61f1eb8..09ef7c336 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/react-native.mdx @@ -29,8 +29,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx index bf1e0c34f..93dc81f8f 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/unity.mdx @@ -43,8 +43,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx index 2679c8473..a71376677 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/web.mdx @@ -26,8 +26,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx index 41a9d8f14..4cc09cfdd 100644 --- a/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/retrieve-messages/project-implementation/windows.mdx @@ -43,8 +43,8 @@ If you have implemented Chat SDK after June 8, 2023, you can retrieve historical The Agora Chat server stores the full message history for a certain period of time depending on your subscribed [Chat plan](../../reference/message-overview#limitations-of-message-storage-duration). After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way: -- 1:1 private chat: Store 500 offline messages/conversation by default; -- Chat Group: Store 200 offline messages/conversation by default; +- 1:1 private chat: Store 500 offline messages by default; +- Chat Group: Store 200 offline messages by default; - Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges. For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx index 91a9e9502..e4fd25bb5 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/android.mdx @@ -379,13 +379,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx index b1819ba24..f62f0acbd 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/flutter.mdx @@ -315,13 +315,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx index 2c800d832..8300e2fd8 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/ios.mdx @@ -390,13 +390,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx index efd30c982..b42c16565 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/react-native.mdx @@ -242,13 +242,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx index b6633132e..ecd1ee3de 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/unity.mdx @@ -443,13 +443,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx index 9f37c8b87..bc2ad0e81 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/web.mdx @@ -556,13 +556,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. diff --git a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx index bc63ea80d..b3b0a3626 100644 --- a/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx +++ b/shared/chat-sdk/client-api/messages/send-receive-messages/project-implementation/windows.mdx @@ -443,13 +443,7 @@ For further details see [Multiple messages forwarding limitations](../../referen ### Modify sent messages -Every end user or chat group member may edit messages that they have sent. - -The process of modifying a message is as follows: - -1. The user calls the API of the SDK to modify a message. -1. The message stored on the server is called back to the SDK after the modification is successful. -1. The SDK modifies the message on the client. After a successful modification, the SDK calls back the modified message to the user. +Every end user or chat group member may edit messages that they have sent. The client API below, when called, will allow the SDK to modify a message. There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification. From c6559310740ba6d51bbd6c67782ba4734bc5b5c9 Mon Sep 17 00:00:00 2001 From: atovpeko Date: Wed, 6 Dec 2023 12:44:25 +0200 Subject: [PATCH 37/37] Release date --- agora-chat/reference/downloads.mdx | 2 +- shared/chat-sdk/reference/release-notes/android.mdx | 2 +- shared/chat-sdk/reference/release-notes/flutter.mdx | 2 +- shared/chat-sdk/reference/release-notes/ios.mdx | 2 +- shared/chat-sdk/reference/release-notes/react-native.mdx | 2 +- shared/chat-sdk/reference/release-notes/restful.mdx | 6 +++--- shared/chat-sdk/reference/release-notes/unity.mdx | 2 +- shared/chat-sdk/reference/release-notes/web.mdx | 2 +- shared/chat-sdk/reference/release-notes/windows.mdx | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/agora-chat/reference/downloads.mdx b/agora-chat/reference/downloads.mdx index 14129f2e9..5b0cca3d6 100644 --- a/agora-chat/reference/downloads.mdx +++ b/agora-chat/reference/downloads.mdx @@ -21,7 +21,7 @@ Download the demo for to e - **Demo**: - - Agora Chat demo app for + - Agora Chat demo app for Android - **Sample**: - Agora Chat sample for Android diff --git a/shared/chat-sdk/reference/release-notes/android.mdx b/shared/chat-sdk/reference/release-notes/android.mdx index 4981bc812..ef9d3af49 100644 --- a/shared/chat-sdk/reference/release-notes/android.mdx +++ b/shared/chat-sdk/reference/release-notes/android.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/flutter.mdx b/shared/chat-sdk/reference/release-notes/flutter.mdx index a40fa1d21..48d484099 100644 --- a/shared/chat-sdk/reference/release-notes/flutter.mdx +++ b/shared/chat-sdk/reference/release-notes/flutter.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/ios.mdx b/shared/chat-sdk/reference/release-notes/ios.mdx index 7ce01dafa..90987d7a6 100644 --- a/shared/chat-sdk/reference/release-notes/ios.mdx +++ b/shared/chat-sdk/reference/release-notes/ios.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/react-native.mdx b/shared/chat-sdk/reference/release-notes/react-native.mdx index ecdf06801..41a884bcf 100644 --- a/shared/chat-sdk/reference/release-notes/react-native.mdx +++ b/shared/chat-sdk/reference/release-notes/react-native.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/restful.mdx b/shared/chat-sdk/reference/release-notes/restful.mdx index 65eed2d4c..658de3aa8 100644 --- a/shared/chat-sdk/reference/release-notes/restful.mdx +++ b/shared/chat-sdk/reference/release-notes/restful.mdx @@ -3,8 +3,8 @@ 1. Added new REST APIs for management of custom attributes of group members: -* Setting custom attributes of a group member -* Retrieving all custom attributes of a group member -* Retrieving custom attributes of multiple group members by attribute key + * Setting custom attributes of a group member + * Retrieving all custom attributes of a group member + * Retrieving custom attributes of multiple group members by attribute key 1. Removed the `nickname` parameter from the RESTful APIs for adding one user or multiple users \ No newline at end of file diff --git a/shared/chat-sdk/reference/release-notes/unity.mdx b/shared/chat-sdk/reference/release-notes/unity.mdx index 78436490f..f0b88d153 100644 --- a/shared/chat-sdk/reference/release-notes/unity.mdx +++ b/shared/chat-sdk/reference/release-notes/unity.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/web.mdx b/shared/chat-sdk/reference/release-notes/web.mdx index 9e99cc728..62c18e480 100644 --- a/shared/chat-sdk/reference/release-notes/web.mdx +++ b/shared/chat-sdk/reference/release-notes/web.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features diff --git a/shared/chat-sdk/reference/release-notes/windows.mdx b/shared/chat-sdk/reference/release-notes/windows.mdx index d42287bf8..6aed34bef 100644 --- a/shared/chat-sdk/reference/release-notes/windows.mdx +++ b/shared/chat-sdk/reference/release-notes/windows.mdx @@ -2,7 +2,7 @@ ## v1.2.0 -v1.2.0 was released on November XX, 2023. +v1.2.0 was released on December 6, 2023. #### New features