blob: d5cd4b5d9f96db7b75093f0444d765b46acafc1d [file] [log] [blame]
Sébastien Blin1f915762020-08-03 13:27:42 -04001/*
2 * Copyright (C) 2020 by Savoir-faire Linux
3 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
4 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
5 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
6 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
7 * Author: Isa Nanic <isa.nanic@savoirfairelinux.com>
8 * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include "conversationsadapter.h"
25
26#include "utils.h"
27
28ConversationsAdapter::ConversationsAdapter(QObject *parent)
29 : QmlAdapterBase(parent)
30{}
31
32ConversationsAdapter::~ConversationsAdapter() {}
33
34void
35ConversationsAdapter::initQmlObject()
36{
37 conversationSmartListModel_ = new SmartListModel(LRCInstance::getCurrAccId(), this);
38
39 QMetaObject::invokeMethod(qmlObj_,
40 "setModel",
41 Q_ARG(QVariant, QVariant::fromValue(conversationSmartListModel_)));
42
43 connect(&LRCInstance::behaviorController(),
44 &BehaviorController::showChatView,
45 [this](const QString &accountId, lrc::api::conversation::Info convInfo) {
46 emit showChatView(accountId, convInfo.uid);
47 });
48
49 connectConversationModel();
50}
51
52void
53ConversationsAdapter::backToWelcomePage()
54{
55 deselectConversation();
56 QMetaObject::invokeMethod(qmlObj_, "backToWelcomePage");
57}
58
59void
60ConversationsAdapter::selectConversation(const QString &accountId,
61 const QString &convUid,
62 bool preventSendingSignal)
63{
64 selectConversation(LRCInstance::getConversationFromConvUid(convUid, accountId),
65 preventSendingSignal);
66}
67
68void
69ConversationsAdapter::selectConversation(int index)
70{
71 auto convModel = LRCInstance::getCurrentConversationModel();
72
73 if (convModel == nullptr) {
74 return;
75 }
76
77 const auto item = convModel->filteredConversation(index);
78
79 if (selectConversation(item, false)) {
80 auto convUid = conversationSmartListModel_
81 ->data(conversationSmartListModel_->index(index, 0),
82 static_cast<int>(SmartListModel::Role::UID))
83 .toString();
84 auto &conversation = LRCInstance::getConversationFromConvUid(convUid);
85 /*
86 * If it is calling, show callview (can use showChatView signal, since it will be determined on qml).
87 */
88 if (!conversation.uid.isEmpty()
89 && LRCInstance::getCurrentCallModel()->hasCall(conversation.callId)) {
90 emit showChatView(LRCInstance::getCurrAccId(), conversation.uid);
91 }
92 }
93}
94
95bool
96ConversationsAdapter::selectConversation(const lrc::api::conversation::Info &item,
97 bool preventSendingSignal)
98{
99 /*
100 * accInfo.conversationModel->selectConversation(item.uid) only emit ui
101 * behavior control signals, but sometimes we do not want that,
102 * preventSendingSignal boolean can help us to determine.
103 */
104 if (LRCInstance::getCurrentConvUid() == item.uid) {
105 return false;
106 } else if (item.participants.size() > 0) {
107 auto &accInfo = LRCInstance::getAccountInfo(item.accountId);
108 LRCInstance::setSelectedConvId(item.uid);
109 if (!preventSendingSignal)
110 accInfo.conversationModel->selectConversation(item.uid);
111 accInfo.conversationModel->clearUnreadInteractions(item.uid);
112 return true;
113 }
114}
115
116void
117ConversationsAdapter::deselectConversation()
118{
119 if (LRCInstance::getCurrentConvUid().isEmpty()) {
120 return;
121 }
122
123 auto currentConversationModel = LRCInstance::getCurrentConversationModel();
124
125 if (currentConversationModel == nullptr) {
126 return;
127 }
128
129 currentConversationModel->selectConversation("");
130 LRCInstance::setSelectedConvId();
131}
132
133void
134ConversationsAdapter::accountChangedSetUp(const QString &accountId)
135{
136 /*
137 * Should be called when current account is changed.
138 */
139 auto &accountInfo = LRCInstance::accountModel().getAccountInfo(accountId);
140 currentTypeFilter_ = accountInfo.profileInfo.type;
141 LRCInstance::getCurrentConversationModel()->setFilter(accountInfo.profileInfo.type);
142 updateConversationsFilterWidget();
143
144 connectConversationModel();
145}
146
147void
148ConversationsAdapter::updateConversationsFilterWidget()
149{
150 /*
151 * Update status of "Conversations" and "Invitations".
152 */
153 auto invites = LRCInstance::getCurrentAccountInfo().contactModel->pendingRequestCount();
154 if (invites == 0 && currentTypeFilter_ == lrc::api::profile::Type::PENDING) {
155 currentTypeFilter_ = lrc::api::profile::Type::RING;
156 LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_);
157 }
158 showConversationTabs(invites);
159}
160
161void
162ConversationsAdapter::setConversationFilter(const QString &type)
163{
164 /*
165 * Set conversation filter according to type,
166 * type needs to be recognizable by lrc::api::profile::to_type.
167 */
168 if (type.isEmpty()) {
169 if (LRCInstance::getCurrentAccountInfo().profileInfo.type == lrc::api::profile::Type::RING)
170 setConversationFilter(lrc::api::profile::Type::RING);
171 else
172 setConversationFilter(lrc::api::profile::Type::SIP);
173 } else {
174 setConversationFilter(lrc::api::profile::to_type(type));
175 }
176}
177
178void
179ConversationsAdapter::setConversationFilter(lrc::api::profile::Type filter)
180{
181 if (currentTypeFilter_ == filter) {
182 return;
183 }
184 currentTypeFilter_ = filter;
185 LRCInstance::getCurrentConversationModel()->setFilter(currentTypeFilter_);
186}
187
188bool
189ConversationsAdapter::connectConversationModel()
190{
191 /*
192 * Signal connections
193 */
194 auto currentConversationModel = LRCInstance::getCurrentAccountInfo().conversationModel.get();
195
196 QObject::disconnect(modelSortedConnection_);
197 QObject::disconnect(modelUpdatedConnection_);
198 QObject::disconnect(filterChangedConnection_);
199 QObject::disconnect(newConversationConnection_);
200 QObject::disconnect(conversationRemovedConnection_);
201 QObject::disconnect(conversationClearedConnection);
202 QObject::disconnect(newInteractionConnection_);
203 QObject::disconnect(interactionRemovedConnection_);
204
205 modelSortedConnection_ = QObject::connect(
206 currentConversationModel, &lrc::api::ConversationModel::modelSorted, [this]() {
207 updateConversationsFilterWidget();
208 QMetaObject::invokeMethod(qmlObj_, "updateConversationSmartListView");
209 auto convUid = LRCInstance::getCurrentConversation().uid;
210 auto convModel = LRCInstance::getCurrentConversationModel();
211 auto &conversation = LRCInstance::getConversationFromConvUid(convUid);
212 if (conversation.uid.isEmpty()) {
213 return;
214 }
215 auto contactURI = conversation.participants[0];
216 if (contactURI.isEmpty()
217 || convModel->owner.contactModel->getContact(contactURI).profileInfo.type
218 == lrc::api::profile::Type::TEMPORARY) {
219 return;
220 }
221 QMetaObject::invokeMethod(qmlObj_, "modelSorted", Q_ARG(QVariant, contactURI));
222 });
223
224 modelUpdatedConnection_
225 = QObject::connect(currentConversationModel,
226 &lrc::api::ConversationModel::conversationUpdated,
227 [this](const QString &convUid) {
228 Q_UNUSED(convUid);
229 updateConversationsFilterWidget();
230 QMetaObject::invokeMethod(qmlObj_, "updateConversationSmartListView");
231 });
232
233 filterChangedConnection_ = QObject::connect(
234 currentConversationModel, &lrc::api::ConversationModel::filterChanged, [this]() {
235 QMetaObject::invokeMethod(qmlObj_,
236 "updateSmartList",
237 Q_ARG(QVariant, LRCInstance::getCurrAccId()));
238 updateConversationsFilterWidget();
239 QMetaObject::invokeMethod(qmlObj_, "updateConversationSmartListView");
240 });
241
242 newConversationConnection_
243 = QObject::connect(currentConversationModel,
244 &lrc::api::ConversationModel::newConversation,
245 [this](const QString &convUid) {
246 QMetaObject::invokeMethod(qmlObj_,
247 "updateSmartList",
248 Q_ARG(QVariant,
249 LRCInstance::getCurrAccId()));
250 updateConversationForNewContact(convUid);
251 });
252
253 conversationRemovedConnection_
254 = QObject::connect(currentConversationModel,
255 &lrc::api::ConversationModel::conversationRemoved,
256 [this]() { backToWelcomePage(); });
257
258 conversationClearedConnection
259 = QObject::connect(currentConversationModel,
260 &lrc::api::ConversationModel::conversationCleared,
261 [this](const QString &convUid) {
262 /*
263 * If currently selected,
264 * switch to welcome screen (deselecting current smartlist item ).
265 */
266 if (convUid != LRCInstance::getCurrentConvUid()) {
267 return;
268 }
269 backToWelcomePage();
270 });
271
272 newInteractionConnection_
273 = QObject::connect(currentConversationModel,
274 &lrc::api::ConversationModel::newInteraction,
275 [this] {
276 updateConversationsFilterWidget();
277 QMetaObject::invokeMethod(qmlObj_, "updateConversationSmartListView");
278 });
279
280 currentConversationModel->setFilter("");
281 return true;
282}
283
284void
285ConversationsAdapter::updateConversationForNewContact(const QString &convUid)
286{
287 auto convModel = LRCInstance::getCurrentConversationModel();
288 if (convModel == nullptr) {
289 return;
290 }
291 auto selectedUid = LRCInstance::getCurrentConvUid();
292 auto &conversation = LRCInstance::getConversationFromConvUid(convUid, {}, true);
293 if (!conversation.uid.isEmpty()) {
294 try {
295 auto contact = convModel->owner.contactModel->getContact(conversation.participants[0]);
296 if (!contact.profileInfo.uri.isEmpty() && contact.profileInfo.uri == selectedUid) {
297 LRCInstance::setSelectedConvId(convUid);
298 convModel->selectConversation(convUid);
299 }
300 } catch (...) {
301 return;
302 }
303 }
304}