From 6f9ee90f0ddd3e279c6d9bf0d6148708c669a886 Mon Sep 17 00:00:00 2001 From: Kateryna Kostiuk Date: Tue, 12 Dec 2017 15:13:34 -0500 Subject: [PATCH] contact request: add manager This patch introduce manager to control conversations related to contact request interactions Change-Id: I4e841feb052d014d06bc3f272a1f038b84b086ce Reviewed-by: Andreas Traczyk --- Ring/Ring.xcodeproj/project.pbxproj | 4 + Ring/Ring/AppDelegate.swift | 3 + .../DBHelpers/InteractionDataHelper.swift | 32 ++++++ Ring/Ring/Database/DBManager.swift | 52 +++++---- .../ContactRequestsViewModel.swift | 30 ------ .../Conversation/ConversationViewModel.swift | 16 +-- .../Ring/Services/ContactRequestManager.swift | 102 ++++++++++++++++++ Ring/Ring/Services/ContactsService.swift | 27 +++++ Ring/Ring/Services/ConversationsService.swift | 57 ++++------ Ring/Ring/Services/ServiceEvent.swift | 5 + 10 files changed, 230 insertions(+), 98 deletions(-) create mode 100644 Ring/Ring/Services/ContactRequestManager.swift diff --git a/Ring/Ring.xcodeproj/project.pbxproj b/Ring/Ring.xcodeproj/project.pbxproj index 07c9330..4fa08ea 100644 --- a/Ring/Ring.xcodeproj/project.pbxproj +++ b/Ring/Ring.xcodeproj/project.pbxproj @@ -90,6 +90,7 @@ 0E2D5F551F9145F200D574BF /* LinkNewDeviceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E2D5F541F9145F200D574BF /* LinkNewDeviceCell.xib */; }; 0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */; }; 0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */; }; + 0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */; }; 0E6949791FA7E71C0029B60A /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6949781FA7E71C0029B60A /* BaseViewController.swift */; }; 0E983E6E1FC77C3E0082103E /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E983E6D1FC77C3E0082103E /* ConversationModel.swift */; }; 0E9D84491FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */; }; @@ -335,6 +336,7 @@ 0E2D5F541F9145F200D574BF /* LinkNewDeviceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LinkNewDeviceCell.xib; sourceTree = ""; }; 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellGenerated.swift; sourceTree = ""; }; 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellGenerated.xib; sourceTree = ""; }; + 0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestManager.swift; sourceTree = ""; }; 0E6949781FA7E71C0029B60A /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 0E983E6D1FC77C3E0082103E /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = ""; }; 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTabBarItemViewModel.swift; sourceTree = ""; }; @@ -677,6 +679,7 @@ 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */, 62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */, 0EF78DE21FD0AE3000FC6966 /* ConversationsManager.swift */, + 0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */, ); path = Services; sourceTree = ""; @@ -1553,6 +1556,7 @@ 56AC650E1E85694D00EA1AA9 /* DesignableTextField.swift in Sources */, 1A2D189A1F2642C000B2C785 /* NotificationCenter+Ring.swift in Sources */, 1A2D18FC1F292DAD00B2C785 /* ConversationCell.swift in Sources */, + 0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */, 1A5DC0371F35675E0075E8EF /* ContactRequestCell.swift in Sources */, 1A20417C1F1E56FF00C08435 /* WelcomeViewModel.swift in Sources */, 1A5DC03D1F35678D0075E8EF /* ContactRequestItem.swift in Sources */, diff --git a/Ring/Ring/AppDelegate.swift b/Ring/Ring/AppDelegate.swift index e475b79..fae477b 100644 --- a/Ring/Ring/AppDelegate.swift +++ b/Ring/Ring/AppDelegate.swift @@ -38,6 +38,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private let presenceService = PresenceService(withPresenceAdapter: PresenceAdapter()) private let networkService = NetworkService() private var conversationManager: ConversationsManager? + private var contactRequestManager: ContactRequestManager? public lazy var injectionBag: InjectionBag = { return InjectionBag(withDaemonService: self.daemonService, @@ -78,6 +79,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Chameleon.setGlobalThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light) Chameleon.setRingThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light) + self.contactRequestManager = ContactRequestManager(accountService: self.accountService, contactService: self.contactsService, conversationService: self.conversationsService) + // load accounts during splashscreen // and ask the AppCoordinator to handle the first screen once loading is finished self.conversationManager = ConversationsManager(with: self.conversationsService, accountsService: self.accountService) diff --git a/Ring/Ring/Database/DBHelpers/InteractionDataHelper.swift b/Ring/Ring/Database/DBHelpers/InteractionDataHelper.swift index f218e98..67e0c02 100644 --- a/Ring/Ring/Database/DBHelpers/InteractionDataHelper.swift +++ b/Ring/Ring/Database/DBHelpers/InteractionDataHelper.swift @@ -304,4 +304,36 @@ final class InteractionDataHelper { return false } } + + func insertIfNotExist(item: Interaction) -> Bool { + guard let dataBase = RingDB.instance.ringDB else { + return false + } + + let querySelect = table.filter(accountId == item.accountID && + conversationId == item.conversationID && + body == item.body && + type == item.type) + let queryInsert = table.insert(accountId <- item.accountID, + authorId <- item.authorID, + conversationId <- item.conversationID, + timestamp <- item.timestamp, + body <- item.body, + type <- item.type, + status <- item.status, + daemonId <- item.daemonID) + do { + let rows = try dataBase.scalar(querySelect.count) + if rows == 0 { + let row = try dataBase.run(queryInsert) + guard row > 0 else { + return false + } + return true + } + } catch { + return false + } + return false + } } diff --git a/Ring/Ring/Database/DBManager.swift b/Ring/Ring/Database/DBManager.swift index 577c823..6450fa2 100644 --- a/Ring/Ring/Database/DBManager.swift +++ b/Ring/Ring/Database/DBManager.swift @@ -112,7 +112,7 @@ class DBManager { try interactionHepler.createTable() } - func saveMessage(for accountUri: String, with contactUri: String, message: MessageModel, incoming: Bool) -> Completable { + func saveMessage(for accountUri: String, with contactUri: String, message: MessageModel, incoming: Bool, interactionType: InteractionType) -> Completable { //create completable which will be executed on background thread return Completable.create { [weak self] completable in @@ -150,8 +150,17 @@ class DBManager { guard let conversationID = conversationsID.first else { throw DBBridgingError.saveMessageFailed } - // for now we have only one conversation between two persons(with group chat could be many) - if let success = self?.addMessageTo(conversation: conversationID, account: accountProfile.id, author: author, message: message), success { + var result: Bool? + switch interactionType { + case .text: + // for now we have only one conversation between two persons(with group chat could be many) + result = self?.addMessageTo(conversation: conversationID, account: accountProfile.id, author: author, message: message) + case .contact: + result = self?.addInteractionContactTo(conversation: conversationID, account: accountProfile.id, author: author, message: message) + default: + result = nil + } + if let success = result, success { completable(.completed) } else { completable(.error(DBBridgingError.saveMessageFailed)) @@ -357,27 +366,20 @@ class DBManager { return participants.first } - private func isGenerated(message: MessageModel) -> Bool { - switch message.content { - case GeneratedMessageType.contactRequestAccepted.rawValue: - return true - case GeneratedMessageType.receivedContactRequest.rawValue: - return true - case GeneratedMessageType.sendContactRequest.rawValue: - return true - default: - return false - } - } - private func convertToMessage(interaction: Interaction, author: String) -> MessageModel? { + if interaction.type != InteractionType.text.rawValue && + interaction.type != InteractionType.contact.rawValue { + return nil + } let date = Date(timeIntervalSince1970: TimeInterval(interaction.timestamp)) let message = MessageModel(withId: interaction.daemonID, receivedDate: date, content: interaction.body, author: author, incoming: interaction.incoming) - message.isGenerated = self.isGenerated(message: message) + if interaction.type == InteractionType.contact.rawValue { + message.isGenerated = true + } if let status: InteractionStatus = InteractionStatus(rawValue: interaction.status) { message.status = status.toMessageStatus() } @@ -393,10 +395,24 @@ class DBManager { let interaction = Interaction(defaultID, accountProfileID, authorProfileID, conversationID, Int64(timeInterval), message.content, InteractionType.text.rawValue, - InteractionStatus.unknown.rawValue, message.daemonId, message.incoming ) + InteractionStatus.unknown.rawValue, message.daemonId, + message.incoming) return self.interactionHepler.insert(item: interaction) } + private func addInteractionContactTo(conversation conversationID: Int64, + account accountProfileID: Int64, + author authorProfileID: Int64, + message: MessageModel) -> Bool { + let timeInterval = message.receivedDate.timeIntervalSince1970 + let interaction = Interaction(defaultID, accountProfileID, authorProfileID, + conversationID, Int64(timeInterval), + message.content, InteractionType.contact.rawValue, + InteractionStatus.read.rawValue, message.daemonId, + message.incoming) + return self.interactionHepler.insertIfNotExist(item: interaction) + } + private func getProfile(for profileUri: String, createIfNotExists: Bool) throws -> Profile? { if let profile = try self.profileHepler.selectProfile(accountURI: profileUri) { return profile diff --git a/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift b/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift index 5ff4d91..63189c7 100644 --- a/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift +++ b/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift @@ -49,17 +49,6 @@ class ContactRequestsViewModel: Stateable, ViewModel { self.presenceService = injectionBag.presenceService self.injectionBag = injectionBag - - self.contactsService.contactRequests - .asObservable() - .subscribe(onNext: {[unowned self] contactRequests in - guard let account = self.accountsService.currentAccount else { return } - guard let ringId = contactRequests.last?.ringId else { return } - self.conversationService.generateMessage(ofType: GeneratedMessageType.receivedContactRequest, - forRindId: ringId, - forAccount: account) - }) - .disposed(by: self.disposeBag) } lazy var contactRequestItems: Observable<[ContactRequestItem]> = { @@ -87,25 +76,6 @@ class ContactRequestsViewModel: Stateable, ViewModel { func accept(withItem item: ContactRequestItem) -> Observable { let acceptCompleted = self.contactsService.accept(contactRequest: item.contactRequest, withAccount: self.accountsService.currentAccount!) - - let accountHelper = AccountModelHelper(withAccount: self.accountsService.currentAccount!) - - let message = MessageModel(withId: "", - receivedDate: Date(), - content: GeneratedMessageType.contactRequestAccepted.rawValue, - author: accountHelper.ringId!, - incoming: true) - message.isGenerated = true - self.conversationService.saveMessage(message: message, - toConversationWith: item.contactRequest.ringId, - toAccountId: (self.accountsService.currentAccount?.id)!, - toAccountUri: accountHelper.ringId!, - shouldRefreshConversations: true) - .subscribe(onCompleted: { [unowned self] in - self.log.debug("Message saved") - }) - .disposed(by: disposeBag) - self.presenceService.subscribeBuddy(withAccountId: (self.accountsService.currentAccount?.id)!, withUri: item.contactRequest.ringId, withFlag: true) diff --git a/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift b/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift index 55afadf..8d12548 100644 --- a/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift +++ b/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift @@ -100,9 +100,7 @@ class ConversationViewModel: ViewModel { .subscribe(onNext: { [unowned self] cont in self.inviteButtonIsAvailable.onNext(!cont.confirmed) - if cont.confirmed { - self.generateMessage(ofType: GeneratedMessageType.contactRequestAccepted) - } + }).disposed(by: self.disposeBag) // subscribe to presence updates for the conversation's associated contact @@ -264,15 +262,11 @@ class ConversationViewModel: ViewModel { } func sendContactRequest() { - let contactExists = self.contactsService.contact(withRingId: self.conversation.value.recipientRingId) != nil ? true : false VCardUtils.loadVCard(named: VCardFiles.myProfile.rawValue, inFolder: VCardFolders.profile.rawValue) .subscribe(onSuccess: { [unowned self] (card) in self.contactsService.sendContactRequest(toContactRingId: self.conversation.value.recipientRingId, vCard: card, withAccount: self.accountService.currentAccount!) .subscribe(onCompleted: { [unowned self] in - if !contactExists { - self.generateMessage(ofType: GeneratedMessageType.sendContactRequest) - } self.log.info("contact request sent") }, onError: { [unowned self] (error) in self.log.info(error) @@ -280,9 +274,6 @@ class ConversationViewModel: ViewModel { }) { [unowned self] error in self.contactsService.sendContactRequest(toContactRingId: self.conversation.value.recipientRingId, vCard: nil, withAccount: self.accountService.currentAccount!) .subscribe(onCompleted: { [unowned self] in - if !contactExists { - self.generateMessage(ofType: GeneratedMessageType.sendContactRequest) - } self.log.info("contact request sent") }, onError: { [unowned self] (error) in self.log.info(error) @@ -290,9 +281,4 @@ class ConversationViewModel: ViewModel { }.disposed(by: self.disposeBag) } - func generateMessage(ofType messageType: GeneratedMessageType) { - self.conversationsService.generateMessage(ofType: messageType, - forRindId: self.conversation.value.recipientRingId, - forAccount: self.accountService.currentAccount!) - } } diff --git a/Ring/Ring/Services/ContactRequestManager.swift b/Ring/Ring/Services/ContactRequestManager.swift new file mode 100644 index 0000000..d96a6d3 --- /dev/null +++ b/Ring/Ring/Services/ContactRequestManager.swift @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2017 Savoir-faire Linux Inc. + * + * Author: Kateryna Kostiuk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +import Foundation +import RxSwift + +class ContactRequestManager { + let accountService: AccountsService + let contactService: ContactsService + let conversationService: ConversationsService + let disposeBag = DisposeBag() + + init(accountService: AccountsService, contactService: ContactsService, conversationService: ConversationsService) { + self.accountService = accountService + self.contactService = contactService + self.conversationService = conversationService + self.subscribeToContactEvents() + } + + private func subscribeToContactEvents() { + self.contactService + .sharedResponseStream + .subscribe(onNext: { [unowned self] contactRequestEvent in + + guard let accountID: String = contactRequestEvent.getEventInput(.accountId) else { + return + } + + guard let contactRingId: String = contactRequestEvent.getEventInput(.uri) else { + return + } + + guard let account = self.accountService.getAccount(fromAccountId: accountID) else { + return + } + + guard let ringId = AccountModelHelper(withAccount: account).ringId else { + return + } + + var shouldUpdateConversations = false + if let currentAccount = self.accountService.currentAccount { + if let currentrRingId = AccountModelHelper(withAccount: currentAccount).ringId, currentrRingId == ringId { + shouldUpdateConversations = true + } + } + + var type: GeneratedMessageType + + var date = Date() + if let receivedDate: Date = contactRequestEvent.getEventInput(.date) { + date = receivedDate + } + + switch contactRequestEvent.eventType { + + case ServiceEventType.contactAdded: + + guard let contactConfirmed: Bool = contactRequestEvent.getEventInput(.state) else { + return + } + + if !contactConfirmed { + return + } + type = GeneratedMessageType.contactRequestAccepted + case ServiceEventType.contactRequestSended: + type = GeneratedMessageType.sendContactRequest + case ServiceEventType.contactRequestReceived: + type = GeneratedMessageType.receivedContactRequest + default: + return + } + + self.conversationService.generateMessage(ofType: type, + contactRingId: contactRingId, + accountRingId: ringId, + accountId: account.id, + date: date, + shouldUpdateConversation: shouldUpdateConversations) + + }) + .disposed(by: disposeBag) + } +} diff --git a/Ring/Ring/Services/ContactsService.swift b/Ring/Ring/Services/ContactsService.swift index c489acc..424bd2d 100644 --- a/Ring/Ring/Services/ContactsService.swift +++ b/Ring/Ring/Services/ContactsService.swift @@ -34,14 +34,20 @@ class ContactsService { fileprivate let contactsAdapter: ContactsAdapter fileprivate let log = SwiftyBeaver.self + fileprivate let disposeBag = DisposeBag() let contactRequests = Variable([ContactRequestModel]()) let contacts = Variable([ContactModel]()) let contactStatus = PublishSubject() + fileprivate let responseStream = PublishSubject() + var sharedResponseStream: Observable + init(withContactsAdapter contactsAdapter: ContactsAdapter) { self.contactsAdapter = contactsAdapter + self.responseStream.disposed(by: disposeBag) + self.sharedResponseStream = responseStream.share() ContactsAdapter.delegate = self } @@ -98,6 +104,11 @@ class ContactsService { let success = self.contactsAdapter.acceptTrustRequest(fromContact: contactRequest.ringId, withAccountId: account.id) if success { + var event = ServiceEvent(withEventType: .contactAdded) + event.addEventInput(.accountId, value: account.id) + event.addEventInput(.state, value: true) + event.addEventInput(.uri, value: contactRequest.ringId) + self.responseStream.onNext(event) observable.on(.completed) } else { observable.on(.error(ContactServiceError.acceptTrustRequestFailed)) @@ -133,6 +144,10 @@ class ContactsService { payload = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000) } self.contactsAdapter.sendTrustRequest(toContact: ringId, payload: payload, withAccountId: account.id) + var event = ServiceEvent(withEventType: .contactRequestSended) + event.addEventInput(.accountId, value: account.id) + event.addEventInput(.uri, value: ringId) + self.responseStream.onNext(event) completable(.completed) } catch { completable(.error(ContactServiceError.vCardSerializationFailed)) @@ -204,6 +219,11 @@ extension ContactsService: ContactsAdapterDelegate { receivedDate: receivedDate, accountId: accountId) self.contactRequests.value.append(contactRequest) + var event = ServiceEvent(withEventType: .contactRequestReceived) + event.addEventInput(.accountId, value: accountId) + event.addEventInput(.uri, value: senderAccount) + event.addEventInput(.date, value: receivedDate) + self.responseStream.onNext(event) } else { // If the contact request already exists, update it's relevant data if let contactRequest = self.contactRequest(withRingId: senderAccount) { @@ -223,6 +243,13 @@ extension ContactsService: ContactsAdapterDelegate { if contact.confirmed != confirmed { contact.confirmed = confirmed self.contactStatus.onNext(contact) + if confirmed { + var event = ServiceEvent(withEventType: .contactAdded) + event.addEventInput(.state, value: confirmed) + event.addEventInput(.accountId, value: accountId) + event.addEventInput(.uri, value: uri) + self.responseStream.onNext(event) + } } } //sync contacts with daemon contacts diff --git a/Ring/Ring/Services/ConversationsService.swift b/Ring/Ring/Services/ConversationsService.swift index d448990..d35129d 100644 --- a/Ring/Ring/Services/ConversationsService.swift +++ b/Ring/Ring/Services/ConversationsService.swift @@ -149,7 +149,8 @@ class ConversationsService { self.dbManager.saveMessage(for: toAccountUri, with: recipientRingId, message: message, - incoming: message.incoming) + incoming: message.incoming, + interactionType: InteractionType.text) .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) .subscribe(onCompleted: { [weak self] in if shouldRefreshConversations { @@ -178,44 +179,30 @@ class ConversationsService { .first } + // swiftlint:enable function_parameter_count func generateMessage(ofType messageType: GeneratedMessageType, - forRindId ringId: String, - forAccount account: AccountModel) { + contactRingId: String, + accountRingId: String, + accountId: String, + date: Date, + shouldUpdateConversation: Bool) { - if let conversation = self.findConversation(withRingId: ringId, withAccountId: account.id) { - if self.generatedMessageExists(ofType: messageType, inConversation: conversation) { - return - } - } - - let uri = AccountModelHelper(withAccount: account).ringId + let message = MessageModel(withId: "", receivedDate: date, content: messageType.rawValue, author: accountRingId, incoming: false) + message.isGenerated = true - let accountHelper = AccountModelHelper(withAccount: account) - - let message = self.createMessage(withId: "", - withContent: messageType.rawValue, - byAuthor: accountHelper.ringId!, - generated: true, - incoming: true) - - self.saveMessage(message: message, - toConversationWith: ringId, - toAccountId: account.id, - toAccountUri: uri!, - shouldRefreshConversations: true) + self.dbManager.saveMessage(for: accountRingId, with: contactRingId, message: message, incoming: false, interactionType: InteractionType.contact) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) .subscribe(onCompleted: { [unowned self] in - self.log.debug("Message saved") - }) - .disposed(by: disposeBag) - } - - func generatedMessageExists(ofType messageType: GeneratedMessageType, - inConversation conversation: ConversationModel) -> Bool { - for message in conversation.messages - where message.content == messageType.rawValue { - return true - } - return false + if shouldUpdateConversation { + self.dbManager.getConversationsObservable(for: accountId, accountURI: accountRingId) + .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) + .subscribe(onNext: { conversationsModels in + self.conversations.value = conversationsModels + }) + .disposed(by: (self.disposeBag)) + } + }, onError: { _ in + }).disposed(by: self.disposeBag) } func status(forMessageId messageId: String) -> MessageStatus { diff --git a/Ring/Ring/Services/ServiceEvent.swift b/Ring/Ring/Services/ServiceEvent.swift index 0cee917..047a2e2 100644 --- a/Ring/Ring/Services/ServiceEvent.swift +++ b/Ring/Ring/Services/ServiceEvent.swift @@ -32,6 +32,9 @@ enum ServiceEventType { case messageStateChanged case knownDevicesChanged case exportOnRingEnded + case contactAdded + case contactRequestSended + case contactRequestReceived } /** @@ -46,6 +49,8 @@ enum ServiceEventInput { case messageStatus case messageId case pin + case accountId + case date } /** -- GitLab