- Fix : display name didn't support UTF8. Address created from Factory take a UTF8 string, aswell as setDisplayName

- Show Historic calls
- Handle cursor shapes on mousearea
This commit is contained in:
Julien Wadel 2020-11-18 12:04:06 +01:00
parent e3c6e0cd35
commit e55f218352
73 changed files with 1753 additions and 99 deletions

View file

@ -138,6 +138,8 @@ set(SOURCES
src/components/core/event-count-notifier/AbstractEventCountNotifier.cpp
src/components/file/FileDownloader.cpp
src/components/file/FileExtractor.cpp
src/components/history/HistoryModel.cpp
src/components/history/HistoryProxyModel.cpp
src/components/notifier/Notifier.cpp
src/components/other/clipboard/Clipboard.cpp
src/components/other/colors/Colors.cpp
@ -198,6 +200,8 @@ set(HEADERS
src/components/core/event-count-notifier/AbstractEventCountNotifier.hpp
src/components/file/FileDownloader.hpp
src/components/file/FileExtractor.hpp
src/components/history/HistoryModel.hpp
src/components/history/HistoryProxyModel.hpp
src/components/notifier/Notifier.hpp
src/components/other/clipboard/Clipboard.hpp
src/components/other/colors/Colors.hpp

View file

@ -830,6 +830,25 @@ Server url ikke konfigureret.</translation>
<translation>Det er nødvendigt at genstarte applikationen. Vil du gøre det nu?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Er du sikker at du vil rydde op historikken?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Rediger kontakt</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Tilføj kontakt</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Slet historik</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ Server URL ist nicht konfiguriert.</translation>
<translation>Ein Neustart der Anwendung ist notwendig. Möchten Sie die Anwendung jetzt neu starten?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Möchten Sie diese Historie wirklich löschen?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Kontakt bearbeiten</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Kontakt hinzufügen</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Verlauf löschen</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -832,6 +832,25 @@ Server URL not configured.</translation>
<translation>It is necessary to restart the application. Do you want to restart now?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Are you sure you want to clear this history?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Edit contact</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Add contact</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Delete history</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ URL del servidor no configurada.</translation>
<translation>Es necesario reiniciar la aplicación. ¿Desea reiniciarla ahora?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">¿Estás seguro de que quieres limpiar este historial?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Editar contacto</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Añadir contacto</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Eliminar historial</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ Url du serveur non configurée.</translation>
<translation>Voulez-vous redémarrer maintenant pour prendre en compte ces modifications ?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Êtes-vous sûr de vouloir supprimer cet historique ?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Editer le contact</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Ajouter le contact</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Supprimer l&apos;historique</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ A kiszolgáló URL-je nincs konfigurálva.</translation>
<translation>Az alkalmazás újraindítása szükséges. Szeretné most újraindítani?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Biztosan törölni kívánja ezt az előzményt?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Kapcsolat szerkesztése</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Kapcsolat hozzáadása</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Előzmények törlése</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ URL del server non configurato.</translation>
<translation>È necessario riavviare l&apos;applicazione. Vuoi riavviare ora?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Sei sicuro di voler cancellare questa cronologia?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Modifica contatto</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Aggiungi contatto</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Cancella cronologia</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@
<translation></translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ Nesukonfigūruotas serverio url.</translation>
<translation>Yra būtina paleisti programą naujo. Ar norite tai atlikti dabar?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Ar tikrai norite išvalyti š istoriją?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Redaguoti kontaktą</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Pridėti kontaktą</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Ištrinti istoriją</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ URL do servidor não configurado.</translation>
<translation>É necessário reiniciar o aplicativo. Deseja reiniciar agora?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Tem certeza de que deseja limpar esse histórico?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Editar contato</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Adicionar contato</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Excluir histórico</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@
<translation>Требуется перезапустить приложение. Хотите перезапустить сейчас?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Вы уверены, что хотите очистить эту историю?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Изменить контакт</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Добавить контакт</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Удалить историю</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ Serverwebbadressen är inte konfigurerad.</translation>
<translation>Det är nödvändigt att starta om programmet. Vill du starta om nu?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Är du säker att du vill rensa den här historiken?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Redigera kontakt</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Lägg till kontakt</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Radera historik</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@ Sunucu url&apos;si yapılandırılmadı.</translation>
<translation>Uygulamanın yeniden başlaması gerekiyor. Şimdi yeniden başlatmak ister misiniz?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Bu geçmişi temizlemek istediğinize emin misiniz?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Kişi düzenle</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Kişi ekle</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Geçmişi sil</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@
<translation>Потрібно перезапустити застосунок. Бажаєте перезапустити зараз?</translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished">Ви впевнені, що волієте вичистити цю історію?</translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished">Редагувати контакт</translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished">Додати контакт</translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished">Вилучити історію</translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -830,6 +830,25 @@
<translation></translation>
</message>
</context>
<context>
<name>HistoryView</name>
<message>
<source>removeAllEntriesDescription</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>tooltipContactEdit</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>tooltipContactAdd</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>cleanHistory</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Home</name>
<message>

View file

@ -229,6 +229,7 @@
<file>ui/modules/Common/Form/ListForm.qml</file>
<file>ui/modules/Common/Form/ListItemSelector.js</file>
<file>ui/modules/Common/Form/ListItemSelector.qml</file>
<file>ui/modules/Common/Form/MouseArea.qml</file>
<file>ui/modules/Common/Form/Placements/FormEmptyLine.qml</file>
<file>ui/modules/Common/Form/Placements/FormGroup.qml</file>
<file>ui/modules/Common/Form/Placements/FormHGroup.qml</file>
@ -338,6 +339,9 @@
<file>ui/modules/Linphone/Contact/ContactMessageCounter.qml</file>
<file>ui/modules/Linphone/Contact/Contact.qml</file>
<file>ui/modules/Linphone/Dialog/OnlineInstallerDialog.qml</file>
<file>ui/modules/Linphone/History/History.qml</file>
<file>ui/modules/Linphone/History/History.js</file>
<file>ui/modules/Linphone/History/Event.qml</file>
<file>ui/modules/Linphone/Menus/SipAddressesMenu.qml</file>
<file>ui/modules/Linphone/Misc/MessageCounter.qml</file>
<file>ui/modules/Linphone/Notifications/NotificationBasic.qml</file>
@ -365,6 +369,7 @@
<file>ui/modules/Linphone/Styles/Contact/ContactMessageCounterStyle.qml</file>
<file>ui/modules/Linphone/Styles/Contact/ContactStyle.qml</file>
<file>ui/modules/Linphone/Styles/Dialog/OnlineInstallerDialogStyle.qml</file>
<file>ui/modules/Linphone/Styles/History/HistoryStyle.qml</file>
<file>ui/modules/Linphone/Styles/Menus/SipAddressesMenuStyle.qml</file>
<file>ui/modules/Linphone/Styles/Misc/MessageCounterStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationBasicStyle.qml</file>
@ -428,10 +433,13 @@
<file>ui/views/App/Main/Dialogs/ManageAccount.js</file>
<file>ui/views/App/Main/Dialogs/ManageAccounts.qml</file>
<file>ui/views/App/Main/Home.qml</file>
<file>ui/views/App/Main/HistoryView.qml</file>
<file>ui/views/App/Main/HistoryView.js</file>
<file>ui/views/App/Main/InviteFriends.qml</file>
<file>ui/views/App/Main/MainWindow.js</file>
<file>ui/views/App/Main/MainWindowMenuBar.qml</file>
<file>ui/views/App/Main/MainWindow.qml</file>
<file>ui/views/App/Main/MainWindowTopMenuBar.qml</file>
<file>ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js</file>
<file>ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml</file>
<file>ui/views/App/Settings/Dialogs/SettingsVideoPreview.qml</file>
@ -469,6 +477,7 @@
<file>ui/views/App/Styles/Main/Dialogs/ManageAccountsStyle.qml</file>
<file>ui/views/App/Styles/Main/HomeStyle.qml</file>
<file>ui/views/App/Styles/Main/InviteFriendsStyle.qml</file>
<file>ui/views/App/Styles/Main/HistoryViewStyle.qml</file>
<file>ui/views/App/Styles/Main/MainWindowStyle.qml</file>
<file>ui/views/App/Styles/qmldir</file>
<file>ui/views/App/Styles/Settings/Dialogs/SettingsSipAccountsEditStyle.qml</file>
@ -477,7 +486,6 @@
<file>ui/views/App/Styles/Settings/SettingsAudioStyle.qml</file>
<file>ui/views/App/Styles/Settings/SettingsWindowStyle.qml</file>
<file>assets/images/linphone_logo.svg</file>
<file>ui/views/App/Main/MainWindowTopMenuBar.qml</file>
<file>ui/dev-modules/Colors/Colors.qml</file>
<file>ui/dev-modules/Units/Units.qml</file>
<file>assets/icon.ico</file>

View file

@ -520,6 +520,7 @@ void App::registerTypes () {
registerType<ContactsListProxyModel>("ContactsListProxyModel");
registerType<FileDownloader>("FileDownloader");
registerType<FileExtractor>("FileExtractor");
registerType<HistoryProxyModel>("HistoryProxyModel");
registerType<SipAddressesProxyModel>("SipAddressesProxyModel");
registerType<SoundPlayer>("SoundPlayer");
registerType<TelephoneNumbersModel>("TelephoneNumbersModel");
@ -535,6 +536,7 @@ void App::registerTypes () {
registerUncreatableType<ChatModel>("ChatModel");
registerUncreatableType<ConferenceHelperModel::ConferenceAddModel>("ConferenceAddModel");
registerUncreatableType<ContactModel>("ContactModel");
registerUncreatableType<HistoryModel>("HistoryModel");
registerUncreatableType<SipAddressObserver>("SipAddressObserver");
registerUncreatableType<VcardModel>("VcardModel");
}

View file

@ -41,6 +41,7 @@
#include "core/CoreManager.hpp"
#include "file/FileDownloader.hpp"
#include "file/FileExtractor.hpp"
#include "history/HistoryProxyModel.hpp"
#include "notifier/Notifier.hpp"
#include "presence/OwnPresenceModel.hpp"
#include "settings/AccountSettingsModel.hpp"

View file

@ -111,7 +111,7 @@ void CallsListModel::launchAudioCall (const QString &sipAddress, const QHash<QSt
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()), Utils::appStringToCoreString(iterator.value()));
}
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
core->inviteAddressWithParams(address, params);
}
@ -130,7 +130,7 @@ void CallsListModel::launchVideoCall (const QString &sipAddress) const {
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(true);
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
core->inviteAddressWithParams(address, params);
}

View file

@ -32,6 +32,7 @@
#include "components/chat/ChatModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
@ -145,6 +146,13 @@ bool CoreManager::chatModelExists (const QString &peerAddress, const QString &lo
return mChatModels.contains({ peerAddress, localAddress });
}
HistoryModel* CoreManager::getHistoryModel(){
if(!mHistoryModel){
mHistoryModel = new HistoryModel(this);
emit historyModelCreated(mHistoryModel);
}
return mHistoryModel;
}
// -----------------------------------------------------------------------------
void CoreManager::init (QObject *parent, const QString &configPath) {

View file

@ -37,6 +37,7 @@ class ChatModel;
class ContactsListModel;
class CoreHandlers;
class EventCountNotifier;
class HistoryModel;
class SettingsModel;
class SipAddressesModel;
class VcardModel;
@ -44,9 +45,9 @@ class VcardModel;
class CoreManager : public QObject {
Q_OBJECT;
Q_PROPERTY(QString version READ getVersion CONSTANT);
Q_PROPERTY(QString downloadUrl READ getDownloadUrl CONSTANT);
Q_PROPERTY(int eventCount READ getEventCount NOTIFY eventCountChanged);
Q_PROPERTY(QString version READ getVersion CONSTANT)
Q_PROPERTY(QString downloadUrl READ getDownloadUrl CONSTANT)
Q_PROPERTY(int eventCount READ getEventCount NOTIFY eventCountChanged)
public:
bool started () const {
@ -65,6 +66,8 @@ public:
std::shared_ptr<ChatModel> getChatModel (const QString &peerAddress, const QString &localAddress);
bool chatModelExists (const QString &sipAddress, const QString &localAddress);
HistoryModel* getHistoryModel();
// ---------------------------------------------------------------------------
// Video render lock.
@ -138,6 +141,7 @@ signals:
void coreStarted ();
void chatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void historyModelCreated (HistoryModel *historyModel);
void logsUploaded (const QString &url);
@ -177,6 +181,7 @@ private:
EventCountNotifier *mEventCountNotifier = nullptr;
QHash<QPair<QString, QString>, std::weak_ptr<ChatModel>> mChatModels;
HistoryModel * mHistoryModel = nullptr;
QTimer *mCbsTimer = nullptr;

View file

@ -25,6 +25,7 @@
#include "components/chat/ChatModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/Utils.hpp"
@ -40,6 +41,10 @@ AbstractEventCountNotifier::AbstractEventCountNotifier (QObject *parent) : QObje
coreManager, &CoreManager::chatModelCreated,
this, &AbstractEventCountNotifier::handleChatModelCreated
);
QObject::connect(
coreManager, &CoreManager::historyModelCreated,
this, &AbstractEventCountNotifier::handleHistoryModelCreated
);
QObject::connect(
coreManager->getHandlers().get(), &CoreHandlers::messageReceived,
this, &AbstractEventCountNotifier::updateUnreadMessageCount
@ -98,11 +103,26 @@ void AbstractEventCountNotifier::handleChatModelCreated (const shared_ptr<ChatMo
);
QObject::connect(
chatModelPtr, &ChatModel::focused,
this, [this, chatModelPtr]() { handleChatModelFocused(chatModelPtr); }
this, [this, chatModelPtr]() { handleResetMissedCalls(chatModelPtr); }
);
QObject::connect(
chatModelPtr, &ChatModel::messageCountReset,
this, [this, chatModelPtr]() { handleResetMissedCalls(chatModelPtr); }
);
}
void AbstractEventCountNotifier::handleChatModelFocused (ChatModel *chatModel) {
void AbstractEventCountNotifier::handleHistoryModelCreated (HistoryModel *historyModel) {
QObject::connect(historyModel, &HistoryModel::callCountReset
, this, &AbstractEventCountNotifier::handleResetAllMissedCalls);
}
void AbstractEventCountNotifier::handleResetAllMissedCalls () {
mMissedCalls.clear();
internalnotifyEventCount();
}
void AbstractEventCountNotifier::handleResetMissedCalls (ChatModel *chatModel) {
auto it = mMissedCalls.find({ Utils::cleanSipAddress(chatModel->getPeerAddress()), Utils::cleanSipAddress(chatModel->getLocalAddress()) });
if (it != mMissedCalls.cend()) {
mMissedCalls.erase(it);

View file

@ -35,6 +35,7 @@ namespace linphone {
class CallModel;
class ChatModel;
class HistoryModel;
class AbstractEventCountNotifier : public QObject {
Q_OBJECT;
@ -68,7 +69,11 @@ private:
void handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void handleChatModelFocused (ChatModel *chatModel);
void handleHistoryModelCreated (HistoryModel *historyModel);
void handleResetAllMissedCalls ();
void handleResetMissedCalls (ChatModel *chatModel);
void handleCallMissed (CallModel *callModel);
QHash<ConferenceId, int> mMissedCalls;

View file

@ -0,0 +1,256 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <QDateTime>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QTimer>
#include <QUuid>
#include <QMessageBox>
#include <QUrlQuery>
#include <QImageReader>
#include "app/App.hpp"
#include "app/paths/Paths.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
#include "HistoryModel.hpp"
// =============================================================================
using namespace std;
static inline void fillCallStartEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = HistoryModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<HistoryModel::CallStatus>(callLog->getStatus());
dest["isStart"] = true;
dest["sipAddress"] = Utils::coreStringToAppString(callLog->getRemoteAddress()->asString());
}
static inline void fillCallEndEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = HistoryModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000);
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<HistoryModel::CallStatus>(callLog->getStatus());
dest["isStart"] = false;
dest["sipAddress"] = Utils::coreStringToAppString(callLog->getRemoteAddress()->asString());
}
// -----------------------------------------------------------------------------
HistoryModel::HistoryModel (QObject *parent) :QAbstractListModel(parent){
CoreManager *coreManager = CoreManager::getInstance();
mCoreHandlers = coreManager->getHandlers();
setSipAddresses();
CoreHandlers *coreHandlers = mCoreHandlers.get();
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &HistoryModel::handleCallStateChanged);
}
HistoryModel::~HistoryModel () {
}
QHash<int, QByteArray> HistoryModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Roles::HistoryEntry] = "$historyEntry";
roles[Roles::SectionDate] = "$sectionDate";
return roles;
}
int HistoryModel::rowCount (const QModelIndex &) const {
return mEntries.count();
}
QVariant HistoryModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mEntries.count())
return QVariant();
switch (role) {
case Roles::HistoryEntry: {
auto &data = mEntries[row].first;
return QVariant::fromValue(data);
}
case Roles::SectionDate:
return QVariant::fromValue(mEntries[row].first["timestamp"].toDate());
}
return QVariant();
}
bool HistoryModel::removeRow (int row, const QModelIndex &) {
return removeRows(row, 1);
}
bool HistoryModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mEntries.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i) {
removeEntry(mEntries[row]);
mEntries.removeAt(row);
}
endRemoveRows();
if (mEntries.count() == 0)
emit allEntriesRemoved();
else if (limit == mEntries.count())
emit lastEntryRemoved();
emit focused();// Removing rows is like having focus. Don't wait asynchronous events.
return true;
}
void HistoryModel::setSipAddresses () {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
mEntries.clear();
QElapsedTimer timer;
timer.start();
// Get calls.
for (auto &callLog : core->getCallLogs())
insertCall(callLog);
qInfo() << QStringLiteral("HistoryModel loaded in %3 milliseconds.").arg(timer.elapsed());
}
// -----------------------------------------------------------------------------
void HistoryModel::removeEntry (int id) {
qInfo() << QStringLiteral("Removing call entry: %1.").arg(id);
if (!removeRow(id))
qWarning() << QStringLiteral("Unable to remove call entry: %1").arg(id);
}
void HistoryModel::removeAllEntries () {
qInfo() << QStringLiteral("Removing all call entries.");
beginResetModel();
for (auto &entry : mEntries)
removeEntry(entry);
mEntries.clear();
endResetModel();
emit allEntriesRemoved();
emit focused();// Removing all entries is like having focus. Don't wait asynchronous events.
}
// -----------------------------------------------------------------------------
void HistoryModel::removeEntry (HistoryEntryData &entry) {
int type = entry.first["type"].toInt();
switch (type) {
case HistoryModel::CallEntry: {
if (entry.first["status"].toInt() == CallStatusSuccess) {
// WARNING: Unable to remove symmetric call here. (start/end)
// We are between `beginRemoveRows` and `endRemoveRows`.
// A solution is to schedule a `removeEntry` call in the Qt main loop.
shared_ptr<void> linphonePtr = entry.second;
QTimer::singleShot(0, this, [this, linphonePtr]() {
auto it = find_if(mEntries.begin(), mEntries.end(), [linphonePtr](const HistoryEntryData &entry) {
return entry.second == linphonePtr;
});
if (it != mEntries.end())
removeEntry(int(distance(mEntries.begin(), it)));
});
}
CoreManager::getInstance()->getCore()->removeCallLog(static_pointer_cast<linphone::CallLog>(entry.second));
break;
}
default:
qWarning() << QStringLiteral("Unknown history entry type: %1.").arg(type);
}
}
void HistoryModel::insertCall (const shared_ptr<linphone::CallLog> &callLog) {
linphone::Call::Status status = callLog->getStatus();
auto insertEntry = [this](
const HistoryEntryData &entry,
const QList<HistoryEntryData>::iterator *start = nullptr
) {
auto it = lower_bound(start ? *start : mEntries.begin(), mEntries.end(), entry, [](const HistoryEntryData &a, const HistoryEntryData &b) {
return a.first["timestamp"] < b.first["timestamp"];
});
int row = int(distance(mEntries.begin(), it));
beginInsertRows(QModelIndex(), row, row);
it = mEntries.insert(it, entry);
endInsertRows();
return it;
};
// Add start call.
QVariantMap start;
fillCallStartEntry(start, callLog);
auto it = insertEntry(qMakePair(start, static_pointer_cast<void>(callLog)));
if (status == linphone::Call::Status::Success) {
QVariantMap end;
fillCallEndEntry(end, callLog);
insertEntry(qMakePair(end, static_pointer_cast<void>(callLog)), &it);
}
}
// -----------------------------------------------------------------------------
void HistoryModel::resetMessageCount () {
emit callCountReset();
}
// -----------------------------------------------------------------------------
void HistoryModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
if (state == linphone::Call::State::End || state == linphone::Call::State::Error)
insertCall(call->getCallLog());
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef HISTORY_MODEL_H_
#define HISTORY_MODEL_H_
#include <linphone++/linphone.hh>
#include <QAbstractListModel>
// =============================================================================
// Fetch all N messages of the History.
// =============================================================================
class CoreHandlers;
class HistoryModel : public QAbstractListModel {
Q_OBJECT
public:
enum Roles {
HistoryEntry = Qt::DisplayRole,
SectionDate
};
enum EntryType {
GenericEntry,
CallEntry
};
Q_ENUM(EntryType)
enum CallStatus {
CallStatusDeclined = int(linphone::Call::Status::Declined),
CallStatusMissed = int(linphone::Call::Status::Missed),
CallStatusSuccess = int(linphone::Call::Status::Success),
CallStatusAborted = int(linphone::Call::Status::Aborted),
CallStatusEarlyAborted = int(linphone::Call::Status::EarlyAborted),
CallStatusAcceptedElsewhere = int(linphone::Call::Status::AcceptedElsewhere),
CallStatusDeclinedElsewhere = int(linphone::Call::Status::DeclinedElsewhere)
};
Q_ENUM(CallStatus)
HistoryModel (QObject *parent = Q_NULLPTR);
virtual ~HistoryModel ();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role) const override;
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
void removeEntry (int id);
void removeAllEntries ();
void resetMessageCount ();
signals:
void allEntriesRemoved ();
void lastEntryRemoved ();
void focused ();
void callCountReset();
private:
typedef QPair<QVariantMap, std::shared_ptr<void>> HistoryEntryData;
void setSipAddresses ();
void removeEntry (HistoryEntryData &entry);
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
mutable QList<HistoryEntryData> mEntries;
std::shared_ptr<CoreHandlers> mCoreHandlers;
};
#endif // HISTORY_MODEL_H_

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <QQuickWindow>
#include "app/App.hpp"
#include "components/core/CoreManager.hpp"
#include "HistoryProxyModel.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
// =============================================================================
using namespace std;
// Fetch the L last filtered history entries.
class HistoryProxyModel::HistoryModelFilter : public QSortFilterProxyModel {
public:
HistoryModelFilter (QObject *parent) : QSortFilterProxyModel(parent) { }
HistoryModel::EntryType getEntryTypeFilter () {
return mEntryTypeFilter;
}
void setEntryTypeFilter (HistoryModel::EntryType type) {
mEntryTypeFilter = type;
invalidate();
}
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &) const override {
if (mEntryTypeFilter == HistoryModel::EntryType::GenericEntry)
return true;
QModelIndex index = sourceModel()->index(sourceRow, 0, QModelIndex());
const QVariantMap data = index.data().toMap();
return data["type"].toInt() == mEntryTypeFilter;
}
private:
HistoryModel::EntryType mEntryTypeFilter = HistoryModel::EntryType::GenericEntry;
};
// =============================================================================
HistoryProxyModel::HistoryProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new HistoryModelFilter(this));
reload();
App *app = App::getInstance();
QObject::connect(app->getMainWindow(), &QWindow::activeChanged, this, [this]() {
handleIsActiveChanged(App::getInstance()->getMainWindow());
});
QQuickWindow *callsWindow = app->getCallsWindow();
if (callsWindow)
QObject::connect(callsWindow, &QWindow::activeChanged, this, [this, callsWindow]() {
handleIsActiveChanged(callsWindow);
});
}
// -----------------------------------------------------------------------------
void HistoryProxyModel::removeAllEntries(){
auto model = CoreManager::getInstance()->getHistoryModel();
if (!model)
return;
model->removeAllEntries();
}
void HistoryProxyModel::removeEntry (int id){
auto model = CoreManager::getInstance()->getHistoryModel();
if (!model)
return;
QModelIndex sourceIndex = mapToSource(index(id, 0));
model->removeEntry(static_cast<HistoryModelFilter *>(sourceModel())->mapToSource(sourceIndex).row() );
}
// -----------------------------------------------------------------------------
void HistoryProxyModel::loadMoreEntries () {
int count = rowCount();
int parentCount = sourceModel()->rowCount();
if (count < parentCount) {
// Do not increase `mMaxDisplayedEntries` if it's not necessary...
// Limit qml calls.
if (count == mMaxDisplayedEntries)
mMaxDisplayedEntries += EntriesChunkSize;
invalidateFilter();
count = rowCount() - count;
if (count > 0)
emit moreEntriesLoaded(count);
}
}
void HistoryProxyModel::setEntryTypeFilter (HistoryModel::EntryType type) {
HistoryModelFilter *HistoryModelFilter = static_cast<HistoryProxyModel::HistoryModelFilter *>(sourceModel());
if (HistoryModelFilter->getEntryTypeFilter() != type) {
HistoryModelFilter->setEntryTypeFilter(type);
emit entryTypeFilterChanged(type);
}
}
// -----------------------------------------------------------------------------
bool HistoryProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const {
return sourceModel()->rowCount() - sourceRow <= mMaxDisplayedEntries;
}
// -----------------------------------------------------------------------------
void HistoryProxyModel::reload () {
mMaxDisplayedEntries = EntriesChunkSize;
static_cast<HistoryModelFilter *>(sourceModel())->setSourceModel(CoreManager::getInstance()->getHistoryModel());
}
void HistoryProxyModel::resetMessageCount(){
auto model = CoreManager::getInstance()->getHistoryModel();
if( model){
model->resetMessageCount();
}
}
// -----------------------------------------------------------------------------
static inline QWindow *getParentWindow (QObject *object) {
App *app = App::getInstance();
const QWindow *mainWindow = app->getMainWindow();
const QWindow *callsWindow = app->getCallsWindow();
for (QObject *parent = object->parent(); parent; parent = parent->parent())
if (parent == mainWindow || parent == callsWindow)
return static_cast<QWindow *>(parent);
return nullptr;
}
void HistoryProxyModel::handleIsActiveChanged (QWindow *window) {
auto model = CoreManager::getInstance()->getHistoryModel();
if (model && window->isActive() && getParentWindow(this) == window) {
model->focused();
model->resetMessageCount();
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef HISTORY_PROXY_MODEL_H_
#define HISTORY_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
#include "HistoryModel.hpp"
// =============================================================================
class QWindow;
class HistoryProxyModel : public QSortFilterProxyModel {
class HistoryModelFilter;
Q_OBJECT;
public:
HistoryProxyModel (QObject *parent = Q_NULLPTR);
Q_INVOKABLE void loadMoreEntries ();
Q_INVOKABLE void setEntryTypeFilter (HistoryModel::EntryType type = HistoryModel::EntryType::CallEntry);
Q_INVOKABLE void removeEntry (int id);
Q_INVOKABLE void removeAllEntries ();
Q_INVOKABLE void resetMessageCount();
signals:
void moreEntriesLoaded (int n);
void entryTypeFilterChanged (HistoryModel::EntryType type);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
private:
void reload ();
void handleIsActiveChanged (QWindow *window);
int mMaxDisplayedEntries = EntriesChunkSize;
static constexpr int EntriesChunkSize = 50;
};
#endif // HISTORY_PROXY_MODEL_H_

View file

@ -30,6 +30,7 @@
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "utils/LinphoneUtils.hpp"
#include "utils/Utils.hpp"
@ -59,6 +60,7 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare
mCoreHandlers = coreManager->getHandlers();
QObject::connect(coreManager, &CoreManager::chatModelCreated, this, &SipAddressesModel::handleChatModelCreated);
QObject::connect(coreManager, &CoreManager::historyModelCreated, this, &SipAddressesModel::handleHistoryModelCreated);
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::handleContactAdded);
@ -261,6 +263,11 @@ void SipAddressesModel::handleChatModelCreated (const shared_ptr<ChatModel> &cha
QObject::connect(ptr, &ChatModel::messageSent, this, &SipAddressesModel::handleMessageSent);
}
void SipAddressesModel::handleHistoryModelCreated (HistoryModel *historyModel) {
QObject::connect(historyModel, &HistoryModel::callCountReset, this, [this] {
handleAllCallCountReset();
});
}
void SipAddressesModel::handleContactAdded (ContactModel *contact) {
for (const auto &sipAddress : contact->getVcardModel()->getSipAddresses())
addOrUpdateSipAddress(sipAddress.toString(), contact);
@ -385,7 +392,16 @@ void SipAddressesModel::handleLastEntryRemoved (ChatModel *chatModel) {
it2->timestamp = map["timestamp"].toDateTime();
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::handleAllCallCountReset () {
for( auto peer = mPeerAddressToSipAddressEntry.begin() ; peer != mPeerAddressToSipAddressEntry.end() ; ++peer){
for( auto local = peer->localAddressToConferenceEntry.begin() ; local != peer->localAddressToConferenceEntry.end() ; ++local){
local->missedCallCount = 0;
updateObservers(peer.key(), local.key(), local->unreadMessageCount, local->missedCallCount);
}
int row = mRefs.indexOf(&(*peer));
emit dataChanged(index(row, 0), index(row, 0));
}
}
void SipAddressesModel::handleMessageCountReset (ChatModel *chatModel) {
const QString &peerAddress = Utils::cleanSipAddress(chatModel->getPeerAddress());
auto it = mPeerAddressToSipAddressEntry.find(peerAddress);

View file

@ -32,6 +32,7 @@ class QUrl;
class ChatModel;
class CoreHandlers;
class HistoryModel;
class SipAddressesModel : public QAbstractListModel {
Q_OBJECT;
@ -82,6 +83,9 @@ public:
// ---------------------------------------------------------------------------
signals:
void sipAddressReset();// The model has been reset
public slots:
void handleAllCallCountReset ();
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
@ -90,6 +94,7 @@ private:
// ---------------------------------------------------------------------------
void handleChatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void handleHistoryModelCreated (HistoryModel *historyModel) ;
void handleContactAdded (ContactModel *contact);
void handleContactRemoved (const ContactModel *contact);
@ -103,6 +108,7 @@ private:
void handleAllEntriesRemoved (ChatModel *chatModel);
void handleLastEntryRemoved (ChatModel *chatModel);
void handleMessageCountReset (ChatModel *chatModel);
void handleMessageSent (const std::shared_ptr<linphone::ChatMessage> &message);

View file

@ -25,6 +25,8 @@
#include "TimelineModel.hpp"
#include <QDebug>
// =============================================================================
@ -72,8 +74,8 @@ QVariant TimelineModel::data (const QModelIndex &index, int role) const {
}
bool TimelineModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return getLocalToConferenceEntry(index.data().toMap())->contains(getCleanedLocalAddress());
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return getLocalToConferenceEntry(index.data().toMap())->contains(getCleanedLocalAddress());
}
bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {

View file

@ -1,6 +1,7 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import Common 1.0
import Common.Styles 1.0
// =============================================================================
@ -76,15 +77,10 @@ Item {
hoverEnabled: true
MouseArea
{
MouseArea {
id: mouseArea
anchors.fill: parent
onPressed: mouse.accepted = false
hoverEnabled: true
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
}
height: parent.height

View file

@ -101,7 +101,6 @@ TextField {
anchors.fill: parent
enabled: !textField.readOnly
hoverEnabled: true
onClicked: fileDialog.open()
}

View file

@ -1,6 +1,7 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import Common 1.0
import Common.Styles 1.0
// =============================================================================
@ -32,14 +33,9 @@ Button {
rightPadding: SmallButtonStyle.rightPadding
}
hoverEnabled: true
MouseArea
{
MouseArea {
id: mouseArea
anchors.fill: parent
onPressed: mouse.accepted = false
hoverEnabled: true
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
}
}

View file

@ -42,7 +42,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
visible: field.readOnly
onWheel: wheel.accepted = true

View file

@ -43,7 +43,7 @@ Controls.TextField {
MouseArea {
anchors.right: parent.right
height: parent.height
hoverEnabled: true
cursorShape: Qt.ArrowCursor
implicitWidth: tools ? tools.width : 0
Rectangle {

View file

@ -0,0 +1,11 @@
import QtQuick 2.7 as Quick
import Common 1.0
import Common.Styles 1.0
Quick.MouseArea {
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
}

View file

@ -1,6 +1,7 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import Common 1.0
import Common.Styles 1.0
// =============================================================================
@ -97,7 +98,7 @@ Switch {
MouseArea {
anchors.fill: parent
onClicked: control.enabled && control.clicked()
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.7
import Common 1.0
// =============================================================================
Item {

View file

@ -68,6 +68,7 @@ Item {
id: builder
MouseArea {
cursorShape: Qt.ArrowCursor
property var _timeout
function _checkPosition (positionEvent) {

View file

@ -2,7 +2,7 @@ import QtQuick 2.7
import QtTest 1.1
import Utils 1.0
import Common 1.0
// =============================================================================
Rectangle {

View file

@ -94,7 +94,6 @@ Rectangle {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: entry.select()
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.7
import Common 1.0
import Common.Styles 1.0
// =============================================================================
@ -42,7 +43,6 @@ Rectangle {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: entry.clicked()
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.7
import Common 1.0
import Common.Styles 1.0
import Utils 1.0

View file

@ -1,6 +1,7 @@
import QtQuick 2.7
import QtQuick.Controls 2.5
import Common 1.0
import Common.Styles 1.0
import 'Window.js' as Logic
@ -57,6 +58,7 @@ StackView{
anchors.fill: parent
hoverEnabled: true
onWheel: wheel.accepted = true
cursorShape: Qt.ArrowCursor
}
Rectangle {
id: content

View file

@ -24,6 +24,7 @@ CommonItemDelegate 1.0 Form/CommonItemDelegate.qml
DroppableTextArea 1.0 Form/DroppableTextArea.qml
ListForm 1.0 Form/ListForm.qml
ListItemSelector 1.0 Form/ListItemSelector.qml
MouseArea 1.0 Form/MouseArea.qml
SearchBox 1.0 Form/SearchBox.qml
Slider 1.0 Form/Slider.qml
StaticListForm 1.0 Form/StaticListForm.qml

View file

@ -14,6 +14,7 @@ Item {
// ---------------------------------------------------------------------------
signal clicked
property alias cursorShape:mouseArea.cursorShape
// ---------------------------------------------------------------------------
@ -94,11 +95,8 @@ Item {
}
MouseArea {
id:mouseArea
anchors.fill: parent
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
onClicked: accountStatus.clicked()
}

View file

@ -148,6 +148,7 @@ Rectangle {
MouseArea {
id: mouseArea
cursorShape: Qt.ArrowCursor
hoverEnabled: true
implicitHeight: layout.height
width: parent.width + parent.anchors.rightMargin

View file

@ -253,10 +253,6 @@ Row {
}
anchors.fill: parent
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
visible: (rectangle.isUploaded || rectangle.isRead) && !$chatEntry.isOutgoing
onClicked: {
@ -296,10 +292,6 @@ Row {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
visible: (rectangle.isError || $chatEntry.status === ChatModel.MessageStatusIdle) && $chatEntry.isOutgoing
onClicked: proxyModel.resendMessage(index)
}

View file

@ -89,6 +89,7 @@ Column {
delegate: MouseArea {
id: dragArea
cursorShape: Qt.ArrowCursor
property bool held: false
@ -189,7 +190,7 @@ Column {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
onPressed: mouse.accepted = false
}

View file

@ -0,0 +1,105 @@
import QtQuick 2.7
import Common 1.0
import Linphone 1.0
import LinphoneUtils 1.0
import Linphone.Styles 1.0
import Utils 1.0
// =============================================================================
Row {
signal entryClicked(string sipAddress)
readonly property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver($historyEntry.sipAddress, '')
property string _type: {
var status = $historyEntry.status
if (status === HistoryModel.CallStatusSuccess) {
if (!$historyEntry.isStart) {
return 'ended_call'
}
return $historyEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === HistoryModel.CallStatusDeclined) {
return $historyEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
if (status === HistoryModel.CallStatusMissed) {
return $historyEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === HistoryModel.CallStatusAborted) {
return $historyEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === HistoryModel.CallStatusEarlyAborted) {
return $historyEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === HistoryModel.CallStatusAcceptedElsewhere) {
return $historyEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === HistoryModel.CallStatusDeclinedElsewhere) {
return $historyEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
return 'unknown_call_event'
}
height: HistoryStyle.entry.lineHeight
spacing: HistoryStyle.entry.message.extraContent.spacing
Icon {
height: parent.height
icon: _type
iconSize: HistoryStyle.entry.event.iconSize
width: HistoryStyle.entry.metaWidth
}
Text {
Component {
// Never created.
// Private data for `lupdate`.
Item {
property var i18n: [
QT_TR_NOOP('declinedIncomingCall'),
QT_TR_NOOP('declinedOutgoingCall'),
QT_TR_NOOP('endedCall'),
QT_TR_NOOP('incomingCall'),
QT_TR_NOOP('missedIncomingCall'),
QT_TR_NOOP('missedOutgoingCall'),
QT_TR_NOOP('outgoingCall')
]
}
}
color: HistoryStyle.entry.event.text.color
font {
bold: true
pointSize: HistoryStyle.entry.event.text.pointSize
}
height: parent.height
text: qsTr(Utils.snakeToCamel(_type)) +' - '
verticalAlignment: Text.AlignVCenter
}
Text {
color: HistoryStyle.entry.event.text.color
font {
bold: true
pointSize: HistoryStyle.entry.event.text.pointSize
}
height: parent.height
text: LinphoneUtils.getContactUsername(_sipAddressObserver)
verticalAlignment: Text.AlignVCenter
MouseArea{
anchors.fill:parent
onClicked:entryClicked($historyEntry.sipAddress)
}
}
ActionButton {
height: HistoryStyle.entry.lineHeight
icon: 'delete'
iconSize: HistoryStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: removeEntry()
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
// =============================================================================
// `Chat.qml` Logic.
// =============================================================================
.import QtQuick 2.7 as QtQuick
.import Linphone 1.0 as Linphone
.import 'qrc:/ui/scripts/LinphoneUtils/linphone-utils.js' as LinphoneUtils
// =============================================================================
function initView () {
history.tryToLoadMoreEntries = false
history.bindToEnd = true
}
function loadMoreEntries () {
if (history.atYBeginning && !history.tryToLoadMoreEntries) {
history.tryToLoadMoreEntries = true
history.positionViewAtBeginning()
container.proxyModel.loadMoreEntries()
}
}
function getComponentFromEntry (historyEntry) {
if (historyEntry.type === Linphone.HistoryModel.CallEntry) {
return 'Event.qml'
}
return ''
}
function handleMoreEntriesLoaded (n) {
history.positionViewAtIndex(n - 1, QtQuick.ListView.Beginning)
history.tryToLoadMoreEntries = false
}
function handleMovementEnded () {
if (history.atYEnd) {
history.bindToEnd = true
}
}
function handleMovementStarted () {
history.bindToEnd = false
}

View file

@ -0,0 +1,205 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
import 'History.js' as Logic
// =============================================================================
Rectangle {
id: container
property alias proxyModel: history.model
signal entryClicked(string sipAddress)
// ---------------------------------------------------------------------------
color: HistoryStyle.color
ColumnLayout {
anchors.fill: parent
spacing: 0
ScrollableListView {
id: history
// -----------------------------------------------------------------------
property bool bindToEnd: false
property bool tryToLoadMoreEntries: true
// -----------------------------------------------------------------------
Layout.fillHeight: true
Layout.fillWidth: true
highlightFollowsCurrentItem: false
section {
criteria: ViewSection.FullString
delegate: sectionHeading
property: '$sectionDate'
}
// -----------------------------------------------------------------------
Component.onCompleted: Logic.initView()
onContentYChanged: Logic.loadMoreEntries()
onMovementEnded: Logic.handleMovementEnded()
onMovementStarted: Logic.handleMovementStarted()
// -----------------------------------------------------------------------
Connections {
target: proxyModel
// When the view is changed (for example `Calls` -> `Messages`),
// the position is set at end and it can be possible to load
// more entries.
onEntryTypeFilterChanged: Logic.initView()
onMoreEntriesLoaded: Logic.handleMoreEntriesLoaded(n)
}
// -----------------------------------------------------------------------
// Heading.
// -----------------------------------------------------------------------
Component {
id: sectionHeading
Item {
implicitHeight: container.height + HistoryStyle.sectionHeading.bottomMargin
width: parent.width
Borders {
id: container
borderColor: HistoryStyle.sectionHeading.border.color
bottomWidth: HistoryStyle.sectionHeading.border.width
implicitHeight: text.contentHeight +
HistoryStyle.sectionHeading.padding * 2 +
HistoryStyle.sectionHeading.border.width * 2
topWidth: HistoryStyle.sectionHeading.border.width
width: parent.width
Text {
id: text
anchors.fill: parent
color: HistoryStyle.sectionHeading.text.color
font {
bold: true
pointSize: HistoryStyle.sectionHeading.text.pointSize
}
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
// Cast section to integer because Qt converts the
// sectionDate in string!!!
text: new Date(section).toLocaleDateString(
Qt.locale(App.locale)
)
}
}
}
}
// -----------------------------------------------------------------------
// Message/Event renderer.
// -----------------------------------------------------------------------
delegate: Rectangle {
id: entry
function isHoverEntry () {
return mouseArea.containsMouse
}
function removeEntry () {
proxyModel.removeEntry(index)
}
anchors {
left: parent ? parent.left : undefined
leftMargin: HistoryStyle.entry.leftMargin
right: parent ? parent.right : undefined
rightMargin: HistoryStyle.entry.deleteIconSize +
HistoryStyle.entry.message.extraContent.spacing +
HistoryStyle.entry.message.extraContent.rightMargin +
HistoryStyle.entry.message.extraContent.leftMargin
}
color: HistoryStyle.color
implicitHeight: layout.height + HistoryStyle.entry.bottomMargin
// ---------------------------------------------------------------------
MouseArea {
id: mouseArea
cursorShape: Qt.ArrowCursor
hoverEnabled: true
implicitHeight: layout.height
width: parent.width + parent.anchors.rightMargin
RowLayout {
id: layout
spacing: 0
width: entry.width
// Display time.
Text {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: HistoryStyle.entry.lineHeight
Layout.preferredWidth: HistoryStyle.entry.time.width
color: HistoryStyle.entry.time.color
font.pointSize: HistoryStyle.entry.time.pointSize
text: $historyEntry.timestamp.toLocaleString(
Qt.locale(App.locale),
'hh:mm'
)
verticalAlignment: Text.AlignVCenter
TooltipArea {
text: $historyEntry.timestamp.toLocaleString(Qt.locale(App.locale))
}
}
// Display content.
Loader {
id:entryLoader
Layout.fillWidth: true
source: Logic.getComponentFromEntry($historyEntry)
}
Connections{
target:entryLoader.item
onEntryClicked:{entryClicked(sipAddress)}
}
}
}
}
}
}
// ---------------------------------------------------------------------------
// Scroll at end if necessary.
// ---------------------------------------------------------------------------
Timer {
interval: 100
repeat: true
running: true
onTriggered: history.bindToEnd && history.positionViewAtEnd()
}
}

View file

@ -101,7 +101,6 @@ Item {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
menu.close()

View file

@ -35,8 +35,6 @@ Notification {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
onClicked: notification._close(notification.handler)
}

View file

@ -65,8 +65,6 @@ Notification {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
onClicked: notification._close(function () {
var uri = Utils.getUriFromSystemPath(notification.fileUri)

View file

@ -71,8 +71,6 @@ Notification {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
onClicked: notification._close(function () {
AccountSettingsModel.setDefaultProxyConfigFromSipAddress(notification.localAddress)

View file

@ -0,0 +1,61 @@
pragma Singleton
import QtQml 2.2
import Colors 1.0
import Units 1.0
// =============================================================================
QtObject {
property color color: Colors.q
property QtObject sectionHeading: QtObject {
property int padding: 5
property int bottomMargin: 20
property QtObject border: QtObject {
property color color: Colors.g10
property int width: 1
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property color color: Colors.g
}
}
property QtObject entry: QtObject {
property int bottomMargin: 10
property int deleteIconSize: 22
property int leftMargin: 18
property int lineHeight: 30
property int metaWidth: 40
property QtObject event: QtObject {
property int iconSize: 18
property QtObject text: QtObject {
property color color: Colors.d
property int pointSize: Units.dp * 10
}
}
property QtObject message: QtObject {
property int padding: 8
property int radius: 4
property QtObject extraContent: QtObject {
property int leftMargin: 10
property int spacing: 5
property int rightMargin: 5
}
}
property QtObject time: QtObject {
property color color: Colors.d
property int pointSize: Units.dp * 10
property int width: 44
}
}
}

View file

@ -34,7 +34,10 @@ QtObject {
}
property QtObject legend: QtObject {
property color backgroundColor: Colors.f
property QtObject backgroundColor: QtObject {
property color normal: Colors.f
property color hovered: Colors.c
}
property color color: Colors.d
property int pointSize: Units.dp * 11
property int height: 30

View file

@ -25,6 +25,8 @@ singleton ContactStyle 1.0 Contact/ContactStyle.qml
singleton OnlineInstallerDialogStyle 1.0 Dialog/OnlineInstallerDialogStyle.qml
singleton HistoryStyle 1.0 History/HistoryStyle.qml
singleton SipAddressesMenuStyle 1.0 Menus/SipAddressesMenuStyle.qml
singleton MessageCounterStyle 1.0 Misc/MessageCounterStyle.qml

View file

@ -55,7 +55,16 @@ Rectangle {
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: TimelineStyle.legend.height
color: TimelineStyle.legend.backgroundColor
color: showHistory.containsMouse?TimelineStyle.legend.backgroundColor.hovered:TimelineStyle.legend.backgroundColor.normal
MouseArea{
id:showHistory
anchors.fill:parent
onClicked: {
view.currentIndex = -1
timeline.entrySelected('')
}
}
Row {
anchors {

View file

@ -50,6 +50,7 @@ ScrollableListView {
// Workaround to handle mouse.
// Without it, the mouse can be given to items list when mouse is hover header.
hoverEnabled: true
cursorShape: Qt.ArrowCursor
Column {
anchors.fill: parent
@ -194,7 +195,7 @@ ScrollableListView {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
RowLayout {
anchors {
@ -215,12 +216,6 @@ ScrollableListView {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
onClicked: sipAddressesView.entryClicked($sipAddress)
}
}

View file

@ -16,6 +16,8 @@ CallStatistics 1.0 Calls/CallStatistics.qml
Chat 1.0 Chat/Chat.qml
History 1.0 History/History.qml
CodecsViewer 1.0 Codecs/CodecsViewer.qml
Avatar 1.0 Contact/Avatar.qml

View file

@ -84,28 +84,31 @@ function _getUsername (str) {
// Returns the username of a contact/sipAddressObserver object or URI string.
function getContactUsername (contact) {
var object = contact.contact || // Contact object from `SipAddressObserver`.
(contact.vcard && contact) // Contact object.
// 1. `object` is a contact.
if (object) {
return object.vcard.username
}
// 2. `object` is just a string.
object = Utils.isString(contact.peerAddress)
? contact.peerAddress // String from `SipAddressObserver`.
: contact // Just a String.
// Use display name.
var name = _getDisplayName(object)
if (name != null) {
return name
}
// Use username.
name = _getUsername(object)
return name == null ? 'Bad EGG' : name
if(contact){
var object = contact.contact || // Contact object from `SipAddressObserver`.
(contact.vcard && contact) // Contact object.
// 1. `object` is a contact.
if (object) {
return object.vcard.username
}
// 2. `object` is just a string.
object = Utils.isString(contact.peerAddress)
? contact.peerAddress // String from `SipAddressObserver`.
: contact // Just a String.
// Use display name.
var name = _getDisplayName(object)
if (name != null) {
return name
}
// Use username.
name = _getUsername(object)
return name == null ? 'Bad EGG' : name
}else
return '';
}
// =============================================================================

View file

@ -101,8 +101,8 @@ Window {
anchors.fill: parent
acceptedButtons: Qt.NoButton
hoverEnabled: true
propagateComposedEvents: true
cursorShape: Qt.ArrowCursor
onEntered: hideButtonsTimer.start()
onExited: hideButtonsTimer.stop()

View file

@ -208,14 +208,10 @@ ColumnLayout {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
MouseArea {
anchors.fill: parent
cursorShape: containsMouse
? Qt.PointingHandCursor
: Qt.ArrowCursor
hoverEnabled: true
onClicked: window.setView('ContactEdit', {
sipAddress: $contact.vcard.sipAddresses[0]

View file

@ -102,9 +102,9 @@ ColumnLayout {
onClicked: window.setView('ContactEdit', {
sipAddress: conversation.peerAddress
})
TooltipArea {
text: Logic.getEditTooltipText()
}
TooltipArea {
text: Logic.getEditTooltipText()
}
}
ActionButton {

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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, see <http://www.gnu.org/licenses/>.
*/
// =============================================================================
// `Conversation.qml` Logic.
// =============================================================================
.import Linphone 1.0 as Linphone
.import 'qrc:/ui/scripts/LinphoneUtils/linphone-utils.js' as LinphoneUtils
.import 'qrc:/ui/scripts/Utils/utils.js' as Utils
// =============================================================================
function removeAllEntries () {
window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), {
descriptionText: qsTr('removeAllEntriesDescription'),
}, function (status) {
if (status) {
historyProxyModel.removeAllEntries()
}
})
}
function getAvatar () {
var contact = historyView._sipAddressObserver.contact
return contact ? contact.vcard.avatar : ''
}
function getEditIcon () {
return historyView._sipAddressObserver && historyView._sipAddressObserver.contact ? 'contact_edit' : 'contact_add'
}
function getEditTooltipText() {
return historyView._sipAddressObserver && historyView._sipAddressObserver.contact ? qsTr('tooltipContactEdit') : qsTr('tooltipContactAdd')
}
function getUsername () {
return LinphoneUtils.getContactUsername(historyView._sipAddressObserver)
}
function updateHistoryFilter (button) {
var HistoryModel = Linphone.HistoryModel
if (button === 0) {
historyProxyModel.setEntryTypeFilter(HistoryModel.GenericEntry)
} else if (button === 1) {
historyProxyModel.setEntryTypeFilter(HistoryModel.CallEntry)
}
}

View file

@ -0,0 +1,150 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import App.Styles 1.0
import 'HistoryView.js' as Logic
// =============================================================================
ColumnLayout {
id: historyView
property string peerAddress
property string fullPeerAddress
readonly property var _sipAddressObserver: peerAddress?SipAddressesModel.getSipAddressObserver((fullPeerAddress?fullPeerAddress:peerAddress), ''):null
// ---------------------------------------------------------------------------
spacing: 0
// ---------------------------------------------------------------------------
// Contact bar.
// ---------------------------------------------------------------------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: peerAddress?HistoryViewStyle.bar.height:HistoryViewStyle.bar.height/2
color: HistoryViewStyle.bar.backgroundColor
RowLayout {
anchors {
fill: parent
leftMargin: HistoryViewStyle.bar.leftMargin
rightMargin: HistoryViewStyle.bar.rightMargin
}
spacing: HistoryViewStyle.bar.spacing
layoutDirection: peerAddress?Qt.LeftToRight :Qt.RightToLeft
Avatar {
id: avatar
Layout.preferredHeight: HistoryViewStyle.bar.avatarSize
Layout.preferredWidth: HistoryViewStyle.bar.avatarSize
image: peerAddress?Logic.getAvatar():null
presenceLevel: historyView._sipAddressObserver?Presence.getPresenceLevel(
historyView._sipAddressObserver.presenceStatus
):null
username: peerAddress?Logic.getUsername():null
visible:peerAddress
}
ContactDescription {
Layout.fillHeight: true
Layout.fillWidth: true
sipAddress: historyView.peerAddress
sipAddressColor: HistoryViewStyle.bar.description.sipAddressColor
username: avatar.username
usernameColor: HistoryViewStyle.bar.description.usernameColor
visible:peerAddress
}
Row {
Layout.fillHeight: true
spacing: HistoryViewStyle.bar.actions.spacing
ActionBar {
anchors.verticalCenter: parent.verticalCenter
iconSize: HistoryViewStyle.bar.actions.call.iconSize
ActionButton {
icon: 'video_call'
visible: peerAddress && SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled
onClicked: CallsListModel.launchVideoCall(historyView.peerAddress)
}
ActionButton {
icon: 'call'
visible: peerAddress && SettingsModel.outgoingCallsEnabled
onClicked: CallsListModel.launchAudioCall(historyView.peerAddress)
}
}
ActionBar {
anchors.verticalCenter: parent.verticalCenter
ActionButton {
icon: Logic.getEditIcon()
iconSize: HistoryViewStyle.bar.actions.edit.iconSize
visible: peerAddress && SettingsModel.contactsEnabled
onClicked: window.setView('ContactEdit', { sipAddress: historyView.peerAddress })
TooltipArea {
text: peerAddress?Logic.getEditTooltipText():''
}
}
ActionButton {
icon: 'delete'
iconSize: HistoryViewStyle.bar.actions.edit.iconSize
onClicked: Logic.removeAllEntries()
TooltipArea {
text: qsTr('cleanHistory')
}
}
}
}
}
}
// ---------------------------------------------------------------------------
// History.
// ---------------------------------------------------------------------------
History {
Layout.fillHeight: true
Layout.fillWidth: true
onEntryClicked:{
historyView.fullPeerAddress=sipAddress
historyView.peerAddress=sipAddress
historyProxyModel.resetMessageCount()
}
proxyModel: HistoryProxyModel {
id: historyProxyModel
Component.onCompleted: {
setEntryTypeFilter()
resetMessageCount()
}
}
}
}

View file

@ -110,6 +110,7 @@ ApplicationWindow {
TooltipArea {
text: AccountSettingsModel.sipAddress
hoveringCursor: Qt.PointingHandCursor
}
onClicked: {
@ -260,12 +261,14 @@ ApplicationWindow {
Layout.fillWidth: true
model: TimelineModel
onEntrySelected: setView('Conversation', {
peerAddress: entry,
localAddress: AccountSettingsModel.sipAddress,
fullPeerAddress: entry,
fullLocalAddress: AccountSettingsModel.fullSipAddress
})
onEntrySelected: (entry?setView('Conversation', {
peerAddress: entry,
localAddress: AccountSettingsModel.sipAddress,
fullPeerAddress: entry,
fullLocalAddress: AccountSettingsModel.fullSipAddress
}):
setView('HistoryView', {})
)
}
}
@ -279,7 +282,7 @@ ApplicationWindow {
Layout.fillWidth: true
source: 'Home.qml'
}
}
}
}
}
@ -287,7 +290,7 @@ ApplicationWindow {
// ---------------------------------------------------------------------------
// Url handlers.
// ---------------------------------------------------------------------------
Connections {
target: UrlHandlers

View file

@ -116,6 +116,7 @@ ApplicationWindow {
anchors.fill: parent
onClicked: konami.forceActiveFocus()
cursorShape: Qt.ArrowCursor
Konami {
id: konami

View file

@ -0,0 +1,50 @@
pragma Singleton
import QtQml 2.2
import Colors 1.0
// =============================================================================
QtObject {
property QtObject bar: QtObject {
property color backgroundColor: Colors.e
property int avatarSize: 60
property int height: 80
property int leftMargin: 40
property int rightMargin: 30
property int spacing: 20
property QtObject actions: QtObject {
property int spacing: 40
property QtObject call: QtObject {
property int iconSize: 40
}
property QtObject del: QtObject {
property int iconSize: 22
}
property QtObject edit: QtObject {
property int iconSize: 22
}
}
property QtObject description: QtObject {
property color sipAddressColor: Colors.g
property color usernameColor: Colors.j
}
}
property QtObject filters: QtObject {
property color backgroundColor: Colors.q
property int height: 51
property int leftMargin: 40
property QtObject border: QtObject {
property color color: Colors.g10
property int bottomWidth: 1
property int topWidth: 0
}
}
}

View file

@ -29,6 +29,7 @@ singleton ContactEditStyle 1.0 Main/ContactEditSty
singleton ContactsStyle 1.0 Main/ContactsStyle.qml
singleton ConversationStyle 1.0 Main/ConversationStyle.qml
singleton HomeStyle 1.0 Main/HomeStyle.qml
singleton HistoryViewStyle 1.0 Main/HistoryViewStyle.qml
singleton InviteFriendsStyle 1.0 Main/InviteFriendsStyle.qml
singleton MainWindowStyle 1.0 Main/MainWindowStyle.qml