From a00423542cc22aebf42121a649206e42b7c093b9 Mon Sep 17 00:00:00 2001 From: Alexey Bukhtin Date: Wed, 18 Mar 2020 13:23:12 +0100 Subject: [PATCH] Improved observing typing events. --- .../Channel Presenter/ChannelPresenter.swift | 15 --------- .../ChatViewController+Composer.swift | 32 +++++++++++-------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Sources/Core/Presenter/Channel Presenter/ChannelPresenter.swift b/Sources/Core/Presenter/Channel Presenter/ChannelPresenter.swift index 8ec9f79c3f2..f72cc5893f5 100644 --- a/Sources/Core/Presenter/Channel Presenter/ChannelPresenter.swift +++ b/Sources/Core/Presenter/Channel Presenter/ChannelPresenter.swift @@ -55,7 +55,6 @@ public final class ChannelPresenter: Presenter { /// Show statuses separators, e.g. Today public private(set) var showStatuses = true - private var startedTyping = false let lastMessageAtomic = Atomic() /// The last parsed message from WebSocket events. @@ -263,21 +262,7 @@ extension ChannelPresenter { // MARK: - Send Event extension ChannelPresenter { - /// Send a typing event. - public func sendEvent(isTyping: Bool) -> Observable { - guard parentMessage == nil && isTyping != startedTyping else { - return .empty() - } - - startedTyping = isTyping - - return channel - .send(eventType: isTyping ? .typingStart : .typingStop) - .observeOn(MainScheduler.instance) - } - /// Send Read event if the app is active. - /// /// - Returns: an observable completion. public func markReadIfPossible() -> Observable { guard InternetConnection.shared.isAvailable, channel.config.readEventsEnabled else { diff --git a/Sources/UI/Chat/Chat View Controller/ChatViewController+Composer.swift b/Sources/UI/Chat/Chat View Controller/ChatViewController+Composer.swift index 2d8ec9899d6..47e1400494a 100644 --- a/Sources/UI/Chat/Chat View Controller/ChatViewController+Composer.swift +++ b/Sources/UI/Chat/Chat View Controller/ChatViewController+Composer.swift @@ -14,7 +14,6 @@ import RxSwift import RxCocoa // MARK: Setup Keyboard Events - extension Reactive where Base: ChatViewController { var keyboard: Binder { return Binder(base) { chatViewController, keyboardNotification in @@ -90,7 +89,6 @@ public extension ChatViewController { // MARK: Setup extension ChatViewController { - func createComposerView() -> ComposerView { let composerView = ComposerView(frame: .zero) composerView.style = style.composer @@ -98,7 +96,7 @@ extension ChatViewController { } func setupComposerView() { - guard composerView.superview == nil else { + guard composerView.superview == nil, let presenter = channelPresenter else { return } @@ -112,17 +110,23 @@ extension ChatViewController { .subscribe(onNext: { [weak self] in self?.showAddFileView() }) .disposed(by: disposeBag) } - - composerView.textView.rx.text - .skip(1) - .unwrap() - .do(onNext: { [weak self] in self?.dispatchCommands(in: $0) }) - .filter { [weak self] in !$0.isBlank && (self?.channelPresenter?.channel.config.typingEventsEnabled ?? false) } - .buffer(timeSpan: .seconds(3), count: 1, scheduler: MainScheduler.instance) - .flatMapLatest { [weak self] (input) -> Observable in - self?.channelPresenter?.sendEvent(isTyping: !input.isEmpty) ?? .empty() } - .subscribe() - .disposed(by: disposeBag) + + let textViewEvents = composerView.textView.rx.text.skip(1).unwrap().share() + + // Dispatch commands from text view. + textViewEvents.subscribe(onNext: { [weak self] in self?.dispatchCommands(in: $0) }).disposed(by: disposeBag) + + // Send typing events. + if presenter.channel.config.typingEventsEnabled, presenter.parentMessage == nil { + Observable.merge([textViewEvents.map { _ in true }, + textViewEvents.debounce(.seconds(3), scheduler: MainScheduler.instance).map { _ in false }]) + .distinctUntilChanged() + .flatMapLatest({ [weak self] isTyping in + self?.channelPresenter?.channel.send(eventType: isTyping ? .typingStart : .typingStop) ?? .empty() + }) + .subscribe() + .disposed(by: disposeBag) + } composerView.sendButton.rx.tap .subscribe(onNext: { [weak self] in self?.send() })