File indexing completed on 2024-04-28 16:42:52
0001 // SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru> 0002 // 0003 // SPDX-License-Identifier: LicenseRef-KDE-Accepted-GPL 0004 0005 #include "active-call-model.h" 0006 0007 constexpr int CALL_DURATION_UPDATE_DELAY = 1000; 0008 0009 ActiveCallModel::ActiveCallModel(QObject *parent) 0010 : CallModel(parent) 0011 { 0012 } 0013 0014 void ActiveCallModel::sendDtmf(const QString &tones) 0015 { 0016 if (!_callUtils) { 0017 qDebug() << Q_FUNC_INFO << "CallUtils is not initiated"; 0018 return; 0019 } 0020 QString deviceUni; 0021 QString callUni; 0022 _callUtils->sendDtmf(deviceUni, callUni, tones); 0023 } 0024 0025 void ActiveCallModel::dial(const QString &deviceUni, const QString &number) 0026 { 0027 if (!_callUtils) { 0028 qDebug() << Q_FUNC_INFO << "CallUtils is not initiated"; 0029 return; 0030 } 0031 _callUtils->dial(deviceUni, number); 0032 } 0033 0034 QString ActiveCallModel::activeCallUni() 0035 { 0036 QString activeCallUni; 0037 if (_calls.size() < 1) { 0038 qDebug() << Q_FUNC_INFO << "empty active calls list"; 0039 return activeCallUni; 0040 } 0041 for (int i = 0; i < _calls.size(); i++) { 0042 const auto call = _calls.at(i); 0043 if (call.state != DialerTypes::CallState::Terminated) { 0044 return call.id; 0045 } 0046 } 0047 return activeCallUni; 0048 } 0049 0050 QVariant ActiveCallModel::data(const QModelIndex &index, int role) const 0051 { 0052 int row = index.row(); 0053 switch (role) { 0054 case Roles::EventRole: 0055 return _calls[row].id; 0056 case Roles::ProtocolRole: 0057 return _calls[row].protocol; 0058 case Roles::AccountRole: 0059 return _calls[row].account; 0060 case Roles::ProviderRole: 0061 return _calls[row].provider; 0062 case Roles::CommunicationWithRole: 0063 return _calls[row].communicationWith; 0064 case Roles::DirectionRole: 0065 return QVariant::fromValue(_calls[row].direction); 0066 case Roles::StateRole: 0067 return QVariant::fromValue(_calls[row].state); 0068 case Roles::StateReasonRole: 0069 return QVariant::fromValue(_calls[row].stateReason); 0070 case Roles::CallAttemptDurationRole: 0071 return _calls[row].callAttemptDuration; 0072 case Roles::StartedAtRole: 0073 return _calls[row].startedAt; 0074 case Roles::DurationRole: 0075 return _calls[row].duration; 0076 } 0077 return {}; 0078 } 0079 0080 int ActiveCallModel::rowCount(const QModelIndex &parent) const 0081 { 0082 Q_UNUSED(parent) 0083 return _calls.size(); 0084 } 0085 0086 void ActiveCallModel::onUtilsCallAdded(const QString &deviceUni, 0087 const QString &callUni, 0088 const DialerTypes::CallDirection &callDirection, 0089 const DialerTypes::CallState &callState, 0090 const DialerTypes::CallStateReason &callStateReason, 0091 const QString communicationWith) 0092 { 0093 Q_UNUSED(deviceUni); 0094 Q_UNUSED(callUni); 0095 Q_UNUSED(callDirection); 0096 Q_UNUSED(callState); 0097 Q_UNUSED(callStateReason); 0098 if (!_callUtils) { 0099 qDebug() << Q_FUNC_INFO << "CallUtils is not initiated"; 0100 return; 0101 } 0102 _callUtils->fetchCalls(); 0103 setCommunicationWith(communicationWith); 0104 _callsTimer.start(); 0105 } 0106 0107 void ActiveCallModel::onUtilsCallDeleted(const QString &deviceUni, const QString &callUni) 0108 { 0109 Q_UNUSED(deviceUni); 0110 Q_UNUSED(callUni); 0111 if (!_callUtils) { 0112 qDebug() << Q_FUNC_INFO << "CallUtils is not initiated"; 0113 return; 0114 } 0115 _callUtils->fetchCalls(); 0116 _callsTimer.stop(); 0117 } 0118 0119 void ActiveCallModel::onUtilsCallStateChanged(const DialerTypes::CallData &callData) 0120 { 0121 qDebug() << Q_FUNC_INFO << callData.state << callData.stateReason; 0122 auto callState = callData.state; 0123 0124 if (callState == DialerTypes::CallState::Active) { 0125 _callsTimer.start(); 0126 } 0127 if (callState == DialerTypes::CallState::RingingIn) { 0128 _callsTimer.start(); 0129 } 0130 if (callState == DialerTypes::CallState::Terminated) { 0131 _callsTimer.stop(); 0132 } 0133 0134 // find call by id and update all the stuff including the duration 0135 for (int i = 0; i < _calls.size(); i++) { 0136 auto call = _calls.at(i); 0137 if (call.id == callData.id) { 0138 call = callData; 0139 Q_EMIT dataChanged(index(i), index(i)); 0140 return; 0141 } 0142 } 0143 } 0144 0145 void ActiveCallModel::onUtilsCallsChanged(const DialerTypes::CallDataVector &fetchedCalls) 0146 { 0147 qDebug() << Q_FUNC_INFO << _calls.size() << fetchedCalls.size(); 0148 beginResetModel(); 0149 _calls = fetchedCalls; 0150 endResetModel(); 0151 bool active = (_calls.size() > 0); 0152 setActive(active); 0153 if (!active) { 0154 return; 0155 } 0156 bool incoming = false; 0157 for (int i = 0; i < _calls.size(); i++) { 0158 const auto call = _calls.at(i); 0159 // trying to determine current active call 0160 // should be checked could it be improved 0161 // with with DialerTypes::CallDirection 0162 if ((call.state != DialerTypes::CallState::Unknown) && (call.state != DialerTypes::CallState::Held) && (call.state != DialerTypes::CallState::Waiting) 0163 && (call.state != DialerTypes::CallState::Terminated)) { 0164 setCommunicationWith(call.communicationWith); 0165 setDuration(call.duration); 0166 } 0167 if (call.direction == DialerTypes::CallDirection::Incoming) { 0168 if (call.state == DialerTypes::CallState::RingingIn) { 0169 incoming = true; 0170 break; 0171 } 0172 } 0173 } 0174 setIncoming(incoming); 0175 } 0176 0177 bool ActiveCallModel::active() const 0178 { 0179 return _active; 0180 } 0181 0182 void ActiveCallModel::setActive(bool newActive) 0183 { 0184 if (_active == newActive) 0185 return; 0186 _active = newActive; 0187 qDebug() << Q_FUNC_INFO; 0188 Q_EMIT activeChanged(); 0189 } 0190 0191 bool ActiveCallModel::incoming() const 0192 { 0193 return _incoming; 0194 } 0195 0196 void ActiveCallModel::setIncoming(bool newIncoming) 0197 { 0198 if (_incoming == newIncoming) 0199 return; 0200 _incoming = newIncoming; 0201 Q_EMIT incomingChanged(); 0202 } 0203 0204 QString ActiveCallModel::communicationWith() const 0205 { 0206 return _communicationWith; 0207 } 0208 0209 void ActiveCallModel::setCommunicationWith(const QString communicationWith) 0210 { 0211 if (_communicationWith == communicationWith) 0212 return; 0213 _communicationWith = communicationWith; 0214 Q_EMIT communicationWithChanged(); 0215 } 0216 0217 qulonglong ActiveCallModel::duration() const 0218 { 0219 return _duration; 0220 } 0221 0222 void ActiveCallModel::setDuration(qulonglong duration) 0223 { 0224 if (_duration == duration) 0225 return; 0226 _duration = duration; 0227 Q_EMIT durationChanged(); 0228 } 0229 0230 void ActiveCallModel::setCallUtils(org::kde::telephony::CallUtils *callUtils) 0231 { 0232 if (!callUtils) { 0233 qDebug() << Q_FUNC_INFO << "Could not initiate CallUtils interface"; 0234 return; 0235 } 0236 _callUtils = callUtils; 0237 0238 connect(_callUtils, &org::kde::telephony::CallUtils::callStateChanged, this, &ActiveCallModel::onUtilsCallStateChanged); 0239 connect(_callUtils, &org::kde::telephony::CallUtils::callAdded, this, &ActiveCallModel::onUtilsCallAdded); 0240 connect(_callUtils, &org::kde::telephony::CallUtils::callDeleted, this, &ActiveCallModel::onUtilsCallDeleted); 0241 connect(_callUtils, &org::kde::telephony::CallUtils::callsChanged, this, &ActiveCallModel::onUtilsCallsChanged); 0242 0243 _callsTimer.setInterval(CALL_DURATION_UPDATE_DELAY); 0244 connect(&_callsTimer, &QTimer::timeout, this, [this]() { 0245 // minimize the number of method calls by incrementing the duration on the client side too 0246 // see also (D-Bus API Design Guidelines): 0247 // https://dbus.freedesktop.org/doc/dbus-api-design.html 0248 _updateTimers(); 0249 }); 0250 0251 callUtils->fetchCalls(); // TODO: simplify sync 0252 } 0253 0254 void ActiveCallModel::_updateTimers() 0255 { 0256 for (int i = 0; i < _calls.size(); i++) { 0257 auto call = _calls.at(i); 0258 auto callState = call.state; 0259 0260 if (callState == DialerTypes::CallState::RingingIn) { 0261 qDebug() << "incoming call"; 0262 call.callAttemptDuration++; 0263 Q_EMIT dataChanged(index(i), index(i), {CallAttemptDurationRole}); 0264 } 0265 if (callState == DialerTypes::CallState::Active) { 0266 qDebug() << "call started"; 0267 call.duration++; 0268 setDuration(call.duration); 0269 Q_EMIT dataChanged(index(i), index(i), {DurationRole}); 0270 } 0271 } 0272 }