Commit 892a26f1 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Andreas Traczyk

history: save call interactions in history

Change-Id: I0d4af8c25f672db14e6fb6aea87bf4f04447bffb
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent fabff4b6
......@@ -113,7 +113,7 @@
0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */; };
0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */; };
0E44B62F202B9DE40060F71B /* LocalNotificationsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */; };
0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */; };
0E48F9D31FDF150700D6CC08 /* GeneratedInteractionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F9D21FDF150700D6CC08 /* GeneratedInteractionsManager.swift */; };
0E4909611FE97A94005CAA50 /* ActiveLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E4909601FE97A94005CAA50 /* ActiveLabel.framework */; };
0E49096A1FEAB156005CAA50 /* CallsAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0E4909691FEAB156005CAA50 /* CallsAdapter.mm */; };
0E49096C1FEAB225005CAA50 /* CallsAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E49096B1FEAB225005CAA50 /* CallsAdapterDelegate.swift */; };
......@@ -393,7 +393,7 @@
0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellGenerated.swift; sourceTree = "<group>"; };
0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellGenerated.xib; sourceTree = "<group>"; };
0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationsHelper.swift; sourceTree = "<group>"; };
0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestManager.swift; sourceTree = "<group>"; };
0E48F9D21FDF150700D6CC08 /* GeneratedInteractionsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedInteractionsManager.swift; sourceTree = "<group>"; };
0E4909601FE97A94005CAA50 /* ActiveLabel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ActiveLabel.framework; path = Carthage/Build/iOS/ActiveLabel.framework; sourceTree = "<group>"; };
0E4909681FEAB156005CAA50 /* CallsAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CallsAdapter.h; sourceTree = "<group>"; };
0E4909691FEAB156005CAA50 /* CallsAdapter.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = CallsAdapter.mm; sourceTree = "<group>"; };
......@@ -767,7 +767,7 @@
62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */,
62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */,
0EF78DE21FD0AE3000FC6966 /* ConversationsManager.swift */,
0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */,
0E48F9D21FDF150700D6CC08 /* GeneratedInteractionsManager.swift */,
0E49096B1FEAB225005CAA50 /* CallsAdapterDelegate.swift */,
0E49096D1FEAC0DE005CAA50 /* CallsService.swift */,
62AA15C21FFC39C80064A063 /* VideoAdapterDelegate.swift */,
......@@ -1791,7 +1791,7 @@
1A2D189A1F2642C000B2C785 /* NotificationCenter+Ring.swift in Sources */,
0E44B62F202B9DE40060F71B /* LocalNotificationsHelper.swift in Sources */,
1A2D18FC1F292DAD00B2C785 /* ConversationCell.swift in Sources */,
0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */,
0E48F9D31FDF150700D6CC08 /* GeneratedInteractionsManager.swift in Sources */,
0E7CF4DD20165BFB00CD967D /* ButtonsContainerViewModel.swift in Sources */,
0E20E4C72031FF560087C868 /* BlockContactsCell.swift in Sources */,
1A5DC0371F35675E0075E8EF /* ContactRequestCell.swift in Sources */,
......
......@@ -42,7 +42,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
private let networkService = NetworkService()
private let profileService = ProfilesService()
private var conversationManager: ConversationsManager?
private var contactRequestManager: ContactRequestManager?
private var interactionsManager: GeneratedInteractionsManager?
private let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
......@@ -100,8 +100,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// themetize the app
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)
self.interactionsManager = GeneratedInteractionsManager(accountService: self.accountService,
contactService: self.contactsService,
conversationService: self.conversationsService,
callService: self.callService)
// load accounts during splashscreen
// and ask the AppCoordinator to handle the first screen once loading is finished
......
......@@ -154,9 +154,11 @@ class DBManager {
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)
result = self?.addMessageTo(conversation: conversationID, account: accountProfile.id, author: author, interactionType: InteractionType.text, message: message)
case .contact:
result = self?.addInteractionContactTo(conversation: conversationID, account: accountProfile.id, author: author, message: message)
case .call:
result = self?.addMessageTo(conversation: conversationID, account: accountProfile.id, author: author, interactionType: InteractionType.call, message: message)
default:
result = nil
}
......@@ -368,7 +370,8 @@ class DBManager {
private func convertToMessage(interaction: Interaction, author: String) -> MessageModel? {
if interaction.type != InteractionType.text.rawValue &&
interaction.type != InteractionType.contact.rawValue {
interaction.type != InteractionType.contact.rawValue &&
interaction.type != InteractionType.call.rawValue {
return nil
}
let date = Date(timeIntervalSince1970: TimeInterval(interaction.timestamp))
......@@ -377,7 +380,7 @@ class DBManager {
content: interaction.body,
author: author,
incoming: interaction.incoming)
if interaction.type == InteractionType.contact.rawValue {
if interaction.type == InteractionType.contact.rawValue || interaction.type == InteractionType.call.rawValue {
message.isGenerated = true
}
if let status: InteractionStatus = InteractionStatus(rawValue: interaction.status) {
......@@ -390,11 +393,12 @@ class DBManager {
private func addMessageTo(conversation conversationID: Int64,
account accountProfileID: Int64,
author authorProfileID: Int64,
interactionType: InteractionType,
message: MessageModel) -> Bool {
let timeInterval = message.receivedDate.timeIntervalSince1970
let interaction = Interaction(defaultID, accountProfileID, authorProfileID,
conversationID, Int64(timeInterval),
message.content, InteractionType.text.rawValue,
message.content, interactionType.rawValue,
InteractionStatus.unknown.rawValue, message.daemonId,
message.incoming)
return self.interactionHepler.insert(item: interaction)
......
......@@ -39,6 +39,10 @@ enum GeneratedMessageType: String {
case sendContactRequest = "The invitation has been sent"
case receivedContactRequest = "Contact request received"
case contactRequestAccepted = "Contact added"
case missedIncomingCall = "Missed incoming call"
case missedOutgoingCall = "Missed outgoing call"
case incomingCall = "Incoming call"
case outgoingCall = "Outgoing call"
}
class MessageViewModel {
......
......@@ -57,7 +57,7 @@ enum CallDetailKey: String {
class CallModel {
var callId: String = ""
var dateReceived: Date = Date()
var dateReceived: Date?
var participantRingId: String = ""
var displayName: String = ""
var registeredName: String = ""
......@@ -119,7 +119,9 @@ class CallModel {
func update(withDictionary dictionary: [String: String]) {
self.dateReceived = Date()
if self.state == .current && self.dateReceived == nil {
self.dateReceived = Date()
}
if let displayName = dictionary[CallDetailKey.displayNameKey.rawValue], !displayName.isEmpty {
self.displayName = displayName
......
......@@ -53,9 +53,13 @@ class CallsService: CallsAdapterDelegate {
let currentCall = ReplaySubject<CallModel>.create(bufferSize: 1)
let newCall = Variable<CallModel>(CallModel(withCallId: "", callDetails: [:]))
fileprivate let responseStream = PublishSubject<ServiceEvent>()
var sharedResponseStream: Observable<ServiceEvent>
init(withCallsAdapter callsAdapter: CallsAdapter) {
self.callsAdapter = callsAdapter
self.responseStream.disposed(by: disposeBag)
self.sharedResponseStream = responseStream.share()
CallsAdapter.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(self.refuseUnansweredCall(_:)),
name: NSNotification.Name(rawValue: NotificationName.refuseCallFromNotifications.rawValue),
......@@ -156,6 +160,7 @@ class CallsService: CallsAdapterDelegate {
callDetails[CallDetailKey.displayNameKey.rawValue] = userName
callDetails[CallDetailKey.accountIdKey.rawValue] = account.id
callDetails[CallDetailKey.audioOnlyKey.rawValue] = isAudioOnly.toString()
callDetails[CallDetailKey.timeStampStartKey.rawValue] = ""
let call = CallModel(withCallId: ringId, callDetails: callDetails)
call.state = .connecting
call.callType = .outgoing
......@@ -216,9 +221,25 @@ class CallsService: CallsAdapterDelegate {
func didChangeCallState(withCallId callId: String, state: String, stateCode: NSInteger) {
if let callDictionary = self.callsAdapter.callDetails(withCallId: callId) {
//Add or update new call
var call = self.calls[callId]
call?.state = CallState(rawValue: state)!
//Remove from the cache if the call is over and save message to history
if call?.state == .over || call?.state == .failure {
var time = 0.00
if let startTime = call?.dateReceived {
time = Date().timeIntervalSince1970 - startTime.timeIntervalSince1970
}
var event = ServiceEvent(withEventType: .callEnded)
event.addEventInput(.uri, value: call?.participantRingId)
event.addEventInput(.accountId, value: call?.accountId)
event.addEventInput(.callType, value: call?.callType.rawValue)
event.addEventInput(.callTime, value: time)
self.responseStream.onNext(event)
self.currentCall.onNext(call!)
self.calls[callId] = nil
return
}
if call == nil {
call = CallModel(withCallId: callId, callDetails: callDictionary)
self.calls[callId] = call
......@@ -226,24 +247,15 @@ class CallsService: CallsAdapterDelegate {
call?.update(withDictionary: callDictionary)
}
//Update the call
call?.state = CallState(rawValue: state)!
//send vCard
if (call?.state == .ringing && call?.callType == .outgoing) ||
(call?.state == .current && call?.callType == .incoming) {
let accountID = call?.accountId
self.sendVCard(callID: callId, accountID: accountID!)
}
//Emit the call to the observers
self.currentCall.onNext(call!)
//Remove from the cache if the call is over
if call?.state == .over {
// TODO save history
self.calls[callId] = nil
}
}
}
......
......@@ -190,17 +190,18 @@ class ConversationsService {
}
// swiftlint:enable function_parameter_count
func generateMessage(ofType messageType: GeneratedMessageType,
func generateMessage(messageContent: String,
contactRingId: String,
accountRingId: String,
accountId: String,
date: Date,
interactionType: InteractionType,
shouldUpdateConversation: Bool) {
let message = MessageModel(withId: "", receivedDate: date, content: messageType.rawValue, author: accountRingId, incoming: false)
let message = MessageModel(withId: "", receivedDate: date, content: messageContent, author: accountRingId, incoming: false)
message.isGenerated = true
self.dbManager.saveMessage(for: accountRingId, with: contactRingId, message: message, incoming: false, interactionType: InteractionType.contact)
self.dbManager.saveMessage(for: accountRingId, with: contactRingId, message: message, incoming: false, interactionType: interactionType)
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.subscribe(onCompleted: { [unowned self] in
if shouldUpdateConversation {
......
......@@ -21,17 +21,20 @@
import Foundation
import RxSwift
class ContactRequestManager {
class GeneratedInteractionsManager {
let accountService: AccountsService
let contactService: ContactsService
let conversationService: ConversationsService
let callService: CallsService
let disposeBag = DisposeBag()
init(accountService: AccountsService, contactService: ContactsService, conversationService: ConversationsService) {
init(accountService: AccountsService, contactService: ContactsService, conversationService: ConversationsService, callService: CallsService) {
self.accountService = accountService
self.contactService = contactService
self.conversationService = conversationService
self.callService = callService
self.subscribeToContactEvents()
self.subscribeToCallEvents()
}
private func subscribeToContactEvents() {
......@@ -95,11 +98,12 @@ class ContactRequestManager {
return
}
self.conversationService.generateMessage(ofType: type,
self.conversationService.generateMessage(messageContent: type.rawValue,
contactRingId: contactRingId,
accountRingId: ringId,
accountId: account.id,
date: date,
interactionType: InteractionType.contact,
shouldUpdateConversation: shouldUpdateConversations)
})
......@@ -121,4 +125,83 @@ class ContactRequestManager {
}
self.conversationService.deleteConversation(conversation: conversation)
}
private func subscribeToCallEvents() {
self.callService
.sharedResponseStream
.subscribe(onNext: { [unowned self] callEvent in
guard let accountID: String = callEvent.getEventInput(.accountId) else {
return
}
guard let contactRingId: String = callEvent.getEventInput(.uri) else {
return
}
guard let time: Double = callEvent.getEventInput(.callTime) else {
return
}
guard let callType: Int = callEvent.getEventInput(.callType) 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 message = ""
if time > 0 {
let timeString = self.convertSecondsToString(seconds: time)
if callType == CallType.incoming.rawValue {
message = GeneratedMessageType.incomingCall.rawValue + " - " + timeString
} else if callType == CallType.outgoing.rawValue {
message = GeneratedMessageType.outgoingCall.rawValue + " - " + timeString
}
} else {
if callType == CallType.incoming.rawValue {
message = GeneratedMessageType.missedIncomingCall.rawValue
} else if callType == CallType.outgoing.rawValue {
message = GeneratedMessageType.missedOutgoingCall.rawValue
}
}
self.conversationService.generateMessage(messageContent: message,
contactRingId: contactRingId,
accountRingId: ringId,
accountId: account.id,
date: Date(),
interactionType: InteractionType.call,
shouldUpdateConversation: shouldUpdateConversations)
})
.disposed(by: disposeBag)
}
func convertSecondsToString(seconds: Double) -> String {
var string = ""
var reminderSeconds = seconds
let hours = Int(seconds / 3600)
if hours > 0 {
reminderSeconds = seconds.truncatingRemainder(dividingBy: 3600)
string += String(format: "%02d", hours) + ":"
}
let min = Int(reminderSeconds / 60)
let sec = reminderSeconds.truncatingRemainder(dividingBy: 60)
string += String(format: "%02d:%02d", min, Int(sec))
print("string", string)
return string
}
}
......@@ -37,6 +37,7 @@ enum ServiceEventType {
case contactRequestReceived
case contactRequestDiscarded
case proxyEnabled
case callEnded
}
/**
......@@ -53,6 +54,8 @@ enum ServiceEventInput {
case pin
case accountId
case date
case callType
case callTime
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment