ConversationsService.swift 5.54 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  Copyright (C) 2017 Savoir-faire Linux Inc.
 *
 *  Author: Silbino Gonçalves Matado <silbino.gmatado@savoirfairelinux.com>
 *
 *  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 UIKit
import RxSwift
23
import RealmSwift
24 25 26 27 28 29

class ConversationsService: MessagesAdapterDelegate {

    fileprivate let messageAdapter :MessagesAdapter
    fileprivate let disposeBag = DisposeBag()
    fileprivate let textPlainMIMEType = "text/plain"
30 31
    fileprivate let realm :Realm = try! Realm()
    fileprivate let results :Results<ConversationModel>!
32

33
    var conversations :Observable<Results<ConversationModel>>
34 35 36

    init(withMessageAdapter messageAdapter: MessagesAdapter) {
        self.messageAdapter = messageAdapter
37 38
        self.results = realm.objects(ConversationModel.self)
        self.conversations = Observable.collection(from: results)
39 40 41
        MessagesAdapter.delegate = self
    }

42 43 44
    func sendMessage(withContent content: String,
                     from senderAccount: AccountModel,
                     to recipient: ContactModel) -> Completable {
45

46 47 48
        return Completable.create(subscribe: { [unowned self] completable in
            let contentDict = [self.textPlainMIMEType : content]
            self.messageAdapter.sendMessage(withContent: contentDict, withAccountId: senderAccount.id, to: recipient.ringId)
49

50 51 52 53 54 55
            let accountHelper = AccountModelHelper(withAccount: senderAccount)

            if accountHelper.ringId! != recipient.ringId {
                _ = self.saveMessage(withContent: content, byAuthor: accountHelper.ringId!, toConversationWith: recipient.ringId, currentAccountId: senderAccount.id)
            }

56 57 58 59 60 61
            completable(.completed)

            return Disposables.create {}
        })
    }

62 63 64 65 66 67 68 69
    func addConversation(conversation: ConversationModel) -> Completable {
        return Completable.create(subscribe: { [unowned self] completable in
            try! self.realm.write {
                self.realm.add(conversation)
            }
            completable(.completed)
            return Disposables.create { }
        })
70 71 72 73 74 75
    }

    func saveMessage(withContent content: String,
                     byAuthor author: String,
                     toConversationWith recipientRingId: String,
                     currentAccountId: String) -> Completable {
76 77

        return Completable.create(subscribe: { [unowned self] completable in
78
            let message = MessageModel(withId: 0, receivedDate: Date(), content: content, author: author)
79 80

            //Get conversations for this sender
81 82
            var currentConversation = self.results.filter({ conversation in
                return conversation.recipient?.ringId == recipientRingId
83 84 85 86
            }).first

            //Create a new conversation for this sender if not exists
            if currentConversation == nil {
87
                currentConversation = ConversationModel(withRecipient: ContactModel(withRingId: recipientRingId), accountId: currentAccountId)
88 89 90 91

                try! self.realm.write {
                    self.realm.add(currentConversation!)
                }
92 93 94
            }

            //Add the received message into the conversation
95 96 97
            try! self.realm.write {
                currentConversation?.messages.append(message)
            }
98 99 100 101 102 103 104 105 106 107 108 109 110 111

            completable(.completed)

            return Disposables.create { }

        })
    }

    func status(forMessageId messageId: UInt64) -> MessageStatus {
        return self.messageAdapter.status(forMessageId: messageId)
    }

    func setMessagesAsRead(forConversation conversation: ConversationModel) -> Completable {

112
        return Completable.create(subscribe: { [unowned self] completable in
113 114 115 116 117 118

            //Filter unread messages
            let unreadMessages = conversation.messages.filter({ messages in
                return messages.status != .read
            })

119 120 121 122
            try! self.realm.write {
                for message in unreadMessages {
                    message.status = .read
                }
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
            }

            completable(.completed)

            return Disposables.create { }

        })
    }

    //MARK: Message Adapter delegate

    func didReceiveMessage(_ message: Dictionary<String, String>, from senderAccount: String,
                           to receiverAccountId: String) {

        if let content = message[textPlainMIMEType] {
138
            self.saveMessage(withContent: content, byAuthor: senderAccount, toConversationWith: senderAccount, currentAccountId: receiverAccountId)
139 140 141 142
                .subscribe(onCompleted: {
                    print("Message saved")
                })
                .addDisposableTo(disposeBag)
143 144 145 146 147 148 149 150 151
        }
    }

    func messageStatusChanged(_ status: MessageStatus, for messageId: UInt64,
                              from senderAccountId: String, to receiverAccount: String) {

        print("messageStatusChanged: \(status.rawValue) for: \(messageId) from: \(senderAccountId) to: \(receiverAccount)")
    }
}