From aec60054560db5aaab60b2a6d7e207c471f2fef9 Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 11:07:10 +0300 Subject: [PATCH 01/10] [readme] [service] added intro --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6b896d4..216072e 100755 --- a/README.md +++ b/README.md @@ -146,6 +146,15 @@ Both `textInputAreaView` and `textInputView` must be created in order for `NMess In order to use your custom InputBar, override `func getInputBar()->InputBarView` in `NMessengerViewController`. + +### Integration With Your Chat Service + +The main purpose of chat messages is exchanging them over the network. The topics above only cover the message rendering aspect. However, it might be unclear how to acthaully push your messages to the network or how to render the received ones. Let's dive in... + + + + + ### NMessenger NMessenger can be added to any view. From 4dde58086502f727608d7d551e79125971de9566 Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 11:18:43 +0300 Subject: [PATCH 02/10] [readme] added cocoapods badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 216072e..fe2f0f0 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # ![./NMessenger](https://github.com/eBay/NMessenger/blob/master/Assets/nmessenger.png) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/eBay/NMessenger/blob/master/LICENSE) +![ios](https://cocoapod-badges.herokuapp.com/v/NMessenger/badge.png) NMessenger is a fast, lightweight messenger component built on [AsyncDisplaykit](https://github.com/facebook/AsyncDisplayKit) and written in [Swift](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/). Developers can inherently achieve 60FPS scrolling and smooth transitions with rich content components. From 46517833bb03b0d3451d3cae2729fc982fc1a1ea Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 11:24:52 +0300 Subject: [PATCH 03/10] [docs] [readme] added tasks description --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index fe2f0f0..fa35d49 100755 --- a/README.md +++ b/README.md @@ -152,6 +152,11 @@ In order to use your custom InputBar, override `func getInputBar()->InputBarView The main purpose of chat messages is exchanging them over the network. The topics above only cover the message rendering aspect. However, it might be unclear how to acthaully push your messages to the network or how to render the received ones. Let's dive in... +Messages management the following two sub-tasks : +* sending realtime messages +* receivung realtime messages +* history integration (both sent and received messages) + From 29f6d29f3cfdb4f2da3d43d04e0816f99839d4b8 Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 12:14:08 +0300 Subject: [PATCH 04/10] [docs] [readme] added service protocols --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index fa35d49..4c0ca11 100755 --- a/README.md +++ b/README.md @@ -158,6 +158,34 @@ Messages management the following two sub-tasks : * history integration (both sent and received messages) +Suppose, our chat service is limited to textin. The service, described below, can use any underlying protocol (such as XMPP, Telegram, etc.). `Disclaimer: your chat service might look differently`. + +```swift +public protocol IChatMessage +{ + var text: String { get } + var isIncoming: Bool { get } +} + +public protocol IChatServiceDelegate +{ + func chatServiceDidConnect(_ sender: IChatService) + func chatService(_ sender: IChatService, didSendMessage: IChatMessage) + func chatService(_ sender: IChatService, didReceiveMessage: IChatMessage) + func chatService(_ sender: IChatService, didReceiveHistory: [IChatMessage]]) + + // TODO: error handling methods are skipped for conciseness +} + +public protocol IChatService +{ + func connectAsync() + func disconnectAsync() + + func sendTextAsync(_ message: String) + func loadHistoryAsync() +} +``` From 2ea3ff299d131b1fed66dd5ea6f4c0c8d4a1be2e Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 12:24:06 +0300 Subject: [PATCH 05/10] [docs] [readme] send message example --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 4c0ca11..ca3afa4 100755 --- a/README.md +++ b/README.md @@ -188,6 +188,28 @@ public protocol IChatService ``` +In order to intercept the user's input you do not need any delegate subscriptions. It is done by overriding the `NMessengerViewController.sendText()` instance method. + + +```swift +public class MyChatMessagingVC: NMessengerViewController, IChatServiceDelegate +{ + override func sendText(_ text: String, isIncomingMessage:Bool) -> GeneralMessengerCell + { + let shouldSendToServer = !isIncomingMessage + + if (shouldSendToServer) + { + // trigger network service + self.controller?.sendMessageAsync(text) + } + + // otherwise - just render + return super.sendText(text, isIncomingMessage: isIncomingMessage) + } +} +``` + ### NMessenger From f0062c3130d1d9f91819290d83942fed4816867d Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 13:18:58 +0300 Subject: [PATCH 06/10] [doc] [readme] added notes on `super.sendText()` --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ca3afa4..0baa916 100755 --- a/README.md +++ b/README.md @@ -205,11 +205,19 @@ public class MyChatMessagingVC: NMessengerViewController, IChatServiceDelegate } // otherwise - just render + // `super` is critical to avoid recursion and "just render" return super.sendText(text, isIncomingMessage: isIncomingMessage) } } ``` +I'd like to highlight the importance of using `super.sendText()` at the end of the function. If `self` is used in this case, you're going to +1. end up with infinite recursion +2. eventually crash due to "stack overflow" reason +3. flood the chat with repeated messages + +You can use some other cell contruction code instead. See the ["Content Nodes and Custom Components"](https://github.com/eBay/NMessenger#content-nodes-and-custom-components) section for details. + ### NMessenger From 94c85ea4fc583689d4f70dc42bc3ea15e5ef6780 Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 13:33:42 +0300 Subject: [PATCH 07/10] [readme] re-phrases user's input foreword --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0baa916..1e0dba3 100755 --- a/README.md +++ b/README.md @@ -187,8 +187,11 @@ public protocol IChatService } ``` +Sending a message involves two phases : +1. Find out that the user has typed something and tapped "send" button. In other words, you have to handle the user's input. +2. Pass the user's input to the networking service. This is achieved as a plain method call. -In order to intercept the user's input you do not need any delegate subscriptions. It is done by overriding the `NMessengerViewController.sendText()` instance method. +Intercepting the user's input might be not quite obvious since you do not need any delegate subscriptions. It is done by overriding the `NMessengerViewController.sendText()` instance method. ```swift From 14ff10a2cdcb70f7256b91f47ada8d66219797bf Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 13:42:57 +0300 Subject: [PATCH 08/10] [readme] added handler for incoming messages --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 1e0dba3..3f83e44 100755 --- a/README.md +++ b/README.md @@ -222,6 +222,29 @@ I'd like to highlight the importance of using `super.sendText()` at the end of t You can use some other cell contruction code instead. See the ["Content Nodes and Custom Components"](https://github.com/eBay/NMessenger#content-nodes-and-custom-components) section for details. + +We can break down the process of "receiving a message" in two phases as well. Here they are: +1. Subscribe to events from your service. Usually it's done by one of iOS mechanics such as delegates, `NSNotification` or closures. +2. Render the message using `NMessenger` + +Let's see how it can be done : + +```swift +public class MyChatMessagingVC: NMessengerViewController, IChatServiceDelegate +{ + func chatService(_ sender: IChatService, didReceiveMessage message: IChatMessage) + { + // Using `super` to avoid side effects. + // + super.sendText(message.text, isIncomingMessage: true) + } +} +``` + +So, now your app should be ready to process realtime messaging. + + + ### NMessenger NMessenger can be added to any view. From 2bea3076789cf29fddbb768d87038e8253feedb3 Mon Sep 17 00:00:00 2001 From: Alexander Dodatko Date: Sat, 1 Apr 2017 13:54:33 +0300 Subject: [PATCH 09/10] [readme] added notes on history handling --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 3f83e44..9f61dde 100755 --- a/README.md +++ b/README.md @@ -245,6 +245,43 @@ So, now your app should be ready to process realtime messaging. +When it comes to history handling, one of the approaches might be purging all the messages from `NMessenger` and re-adding them. + +```swift +public class MyChatMessagingVC: NMessengerViewController, IChatServiceDelegate +{ + override func viewDidAppear(_ animated: Bool) + { + super.viewDidAppear(animated) + + // supposing `self._chatService` has been the setup in `viewDidLoad` + // or injected during the screen transition + // + self._chatService.loadHistoryAsync() + } + + + func chatService(_ sender: IChatService, didReceiveHistory: [IChatMessage]]) + { + super.clearALLMessages() + + messageList.forEach + { + // using `super`to avoid side effects + // + _ = super.sendText($0.text, isIncomingMessage: $0.isIncoming) + } + } +} +``` + +This approach might result in poor performance and some unwanted visual effects. +``` +TODO: describe a better approach +``` + + + ### NMessenger NMessenger can be added to any view. From 32b75e12434c7b292479520d5a6885e16f36aea5 Mon Sep 17 00:00:00 2001 From: Aaron Tainter Date: Thu, 31 Aug 2017 08:13:23 -0700 Subject: [PATCH 10/10] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f61dde..deccf65 100755 --- a/README.md +++ b/README.md @@ -154,11 +154,11 @@ The main purpose of chat messages is exchanging them over the network. The topic Messages management the following two sub-tasks : * sending realtime messages -* receivung realtime messages +* receiving realtime messages * history integration (both sent and received messages) -Suppose, our chat service is limited to textin. The service, described below, can use any underlying protocol (such as XMPP, Telegram, etc.). `Disclaimer: your chat service might look differently`. +Suppose, our chat service is limited to text in. The service, described below, can use any underlying protocol (such as XMPP, Telegram, etc.). `Disclaimer: your chat service might look differently`. ```swift public protocol IChatMessage