LINQT-1166 handle complete sip uri login
LINQT-1182 hide waiting timer in local sticker
LINQT-368 share contact (by copying its vcard, may be improved in the future)
fix notif ui
fix waiting room camera
fix missed notifications
windows ui fixes
fix LINQT-1189 start call on click not selected contact changed
This commit is contained in:
Gaelle Braud 2024-05-22 19:34:07 +02:00
parent 5cf6138bdb
commit 305c969bbb
29 changed files with 278 additions and 181 deletions

View file

@ -20,7 +20,6 @@
#include "AccountCore.hpp" #include "AccountCore.hpp"
#include "core/App.hpp" #include "core/App.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeConnection.hpp"
@ -95,6 +94,20 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToCore(&AccountCore::lResetMissedCalls, [this]() { mAccountModelConnection->makeConnectToCore(&AccountCore::lResetMissedCalls, [this]() {
mAccountModelConnection->invokeToModel([this]() { mAccountModel->resetMissedCallsCount(); }); mAccountModelConnection->invokeToModel([this]() { mAccountModel->resetMissedCallsCount(); });
}); });
mAccountModelConnection->makeConnectToCore(&AccountCore::lRefreshNotifications, [this]() {
mAccountModelConnection->invokeToModel([this]() { mAccountModel->refreshUnreadNotifications(); });
});
mCoreModelConnection = QSharedPointer<SafeConnection<AccountCore, CoreModel>>(
new SafeConnection<AccountCore, CoreModel>(me, CoreModel::getInstance()));
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadCallNotificationsChanged, [this]() {
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadMessageNotificationsChanged, [this]() {
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadNotificationsChanged, [this]() {
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
});
} }
QString AccountCore::getContactAddress() const { QString AccountCore::getContactAddress() const {
@ -133,7 +146,7 @@ int AccountCore::getUnreadCallNotifications() const {
void AccountCore::setUnreadCallNotifications(int unread) { void AccountCore::setUnreadCallNotifications(int unread) {
if (mUnreadCallNotifications != unread) { if (mUnreadCallNotifications != unread) {
mUnreadCallNotifications = unread; mUnreadCallNotifications = unread;
emit unreadNotificationsChanged(unread); emit unreadCallNotificationsChanged(unread);
} }
} }
@ -143,7 +156,7 @@ int AccountCore::getUnreadMessageNotifications() const {
void AccountCore::setUnreadMessageNotifications(int unread) { void AccountCore::setUnreadMessageNotifications(int unread) {
if (mUnreadMessageNotifications != unread) { if (mUnreadMessageNotifications != unread) {
mUnreadMessageNotifications = unread; mUnreadMessageNotifications = unread;
emit unreadNotificationsChanged(unread); emit unreadMessageNotificationsChanged(unread);
} }
} }

View file

@ -38,8 +38,9 @@ class AccountCore : public QObject, public AbstractObject {
LinphoneEnums::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged) LinphoneEnums::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged)
Q_PROPERTY(bool isDefaultAccount READ getIsDefaultAccount NOTIFY defaultAccountChanged) Q_PROPERTY(bool isDefaultAccount READ getIsDefaultAccount NOTIFY defaultAccountChanged)
Q_PROPERTY(int unreadNotifications READ getUnreadNotifications NOTIFY unreadNotificationsChanged) Q_PROPERTY(int unreadNotifications READ getUnreadNotifications NOTIFY unreadNotificationsChanged)
Q_PROPERTY(int unreadCallNotifications READ getUnreadCallNotifications NOTIFY unreadNotificationsChanged) Q_PROPERTY(int unreadCallNotifications READ getUnreadCallNotifications NOTIFY unreadCallNotificationsChanged)
Q_PROPERTY(int unreadMessageNotifications READ getUnreadMessageNotifications NOTIFY unreadNotificationsChanged) Q_PROPERTY(
int unreadMessageNotifications READ getUnreadMessageNotifications NOTIFY unreadMessageNotificationsChanged)
public: public:
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account); static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
@ -72,12 +73,15 @@ signals:
void pictureUriChanged(); void pictureUriChanged();
void registrationStateChanged(const QString &message); void registrationStateChanged(const QString &message);
void defaultAccountChanged(bool isDefault); void defaultAccountChanged(bool isDefault);
void unreadNotificationsChanged(int unreadNotifications); void unreadNotificationsChanged(int unread);
void unreadCallNotificationsChanged(int unread);
void unreadMessageNotificationsChanged(int unread);
// Account requests // Account requests
void lSetPictureUri(QString pictureUri); void lSetPictureUri(QString pictureUri);
void lSetDefaultAccount(); void lSetDefaultAccount();
void lResetMissedCalls(); void lResetMissedCalls();
void lRefreshNotifications();
private: private:
QString mContactAddress; QString mContactAddress;
@ -90,6 +94,7 @@ private:
int mUnreadMessageNotifications = 0; int mUnreadMessageNotifications = 0;
std::shared_ptr<AccountModel> mAccountModel; std::shared_ptr<AccountModel> mAccountModel;
QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection; QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection;
QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -36,7 +36,6 @@
class ConferenceCore : public QObject, public AbstractObject { class ConferenceCore : public QObject, public AbstractObject {
Q_OBJECT Q_OBJECT
public: public:
Q_PROPERTY(QString subject READ getSubject NOTIFY subjectChanged)
Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT) Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT)
// Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT) // Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT)
// Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged) // Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged)
@ -72,7 +71,6 @@ public:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
signals: signals:
void subjectChanged();
void isReadyChanged(); void isReadyChanged();
void participantDeviceCountChanged(); void participantDeviceCountChanged();
void activeSpeakerChanged(); void activeSpeakerChanged();

View file

@ -55,8 +55,10 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
mCoreModelConnection->invokeToModel([this]() { mCoreModelConnection->invokeToModel([this]() {
QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>(); QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>();
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
if (!defaultAccount) return;
std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos = std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos =
CoreModel::getInstance()->getCore()->getDefaultAccount()->getConferenceInformationList(); defaultAccount->getConferenceInformationList();
items->push_back(nullptr); // Add Dummy conference for today items->push_back(nullptr); // Add Dummy conference for today
for (auto conferenceInfo : conferenceInfos) { for (auto conferenceInfo : conferenceInfos) {
auto confInfoCore = build(conferenceInfo); auto confInfoCore = build(conferenceInfo);

View file

@ -59,6 +59,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
mJob = Utils::coreStringToAppString(vcard->getJobTitle()); mJob = Utils::coreStringToAppString(vcard->getJobTitle());
mGivenName = Utils::coreStringToAppString(vcard->getGivenName()); mGivenName = Utils::coreStringToAppString(vcard->getGivenName());
mFamilyName = Utils::coreStringToAppString(vcard->getFamilyName()); mFamilyName = Utils::coreStringToAppString(vcard->getFamilyName());
mVCardString = Utils::coreStringToAppString(vcard->asVcard4String());
} }
auto addresses = contact->getAddresses(); auto addresses = contact->getAddresses();
for (auto &address : addresses) { for (auto &address : addresses) {
@ -80,6 +81,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
mIsSaved = false; mIsSaved = false;
mStarred = false; mStarred = false;
} }
connect(this, &FriendCore::addressChanged, &FriendCore::allAddressesChanged); connect(this, &FriendCore::addressChanged, &FriendCore::allAddressesChanged);
connect(this, &FriendCore::phoneNumberChanged, &FriendCore::allAddressesChanged); connect(this, &FriendCore::phoneNumberChanged, &FriendCore::allAddressesChanged);
} }
@ -247,6 +249,10 @@ void FriendCore::onStarredChanged(bool starred) {
emit starredChanged(); emit starredChanged();
} }
QString FriendCore::getVCard() const {
return mVCardString;
}
QList<QVariant> FriendCore::getPhoneNumbers() const { QList<QVariant> FriendCore::getPhoneNumbers() const {
return mPhoneNumberList; return mPhoneNumberList;
} }
@ -480,6 +486,7 @@ void FriendCore::save() { // Save Values to model
mustBeInLinphoneThread(getClassName() + "::save()"); mustBeInLinphoneThread(getClassName() + "::save()");
thisCopy->writeIntoModel(mFriendModel); thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater(); thisCopy->deleteLater();
mVCardString = mFriendModel->getVCardAsString();
mFriendModelConnection->invokeToCore([this]() { saved(); }); mFriendModelConnection->invokeToCore([this]() { saved(); });
setIsSaved(true); setIsSaved(true);
}); });
@ -501,6 +508,7 @@ void FriendCore::save() { // Save Values to model
mCoreModelConnection->invokeToModel([this, thisCopy] { mCoreModelConnection->invokeToModel([this, thisCopy] {
thisCopy->writeIntoModel(mFriendModel); thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater(); thisCopy->deleteLater();
mVCardString = mFriendModel->getVCardAsString();
}); });
saved(); saved();
}); });
@ -514,6 +522,7 @@ void FriendCore::save() { // Save Values to model
auto core = CoreModel::getInstance()->getCore(); auto core = CoreModel::getInstance()->getCore();
thisCopy->writeIntoModel(mFriendModel); thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater(); thisCopy->deleteLater();
mVCardString = mFriendModel->getVCardAsString();
bool created = bool created =
(core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK); (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
if (created) { if (created) {

View file

@ -87,6 +87,8 @@ public:
bool getStarred() const; bool getStarred() const;
void onStarredChanged(bool starred); void onStarredChanged(bool starred);
Q_INVOKABLE QString getVCard() const;
QList<QVariant> getPhoneNumbers() const; QList<QVariant> getPhoneNumbers() const;
QVariant getPhoneNumberAt(int index) const; QVariant getPhoneNumberAt(int index) const;
Q_INVOKABLE void appendPhoneNumber(const QString &label, const QString &number); Q_INVOKABLE void appendPhoneNumber(const QString &label, const QString &number);
@ -164,6 +166,7 @@ protected:
QString mDefaultAddress; QString mDefaultAddress;
QString mPictureUri; QString mPictureUri;
bool mIsSaved; bool mIsSaved;
QString mVCardString;
std::shared_ptr<FriendModel> mFriendModel; std::shared_ptr<FriendModel> mFriendModel;
QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection; QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection;
QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection;

View file

@ -176,7 +176,7 @@ QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantM
engine->deleteLater(); engine->deleteLater();
exit(-1); exit(-1);
} else { } else {
qWarning() << engine->rootObjects()[0]; lDebug() << engine->rootObjects()[0];
auto window = qobject_cast<QQuickWindow *>(obj); auto window = qobject_cast<QQuickWindow *>(obj);
if (window) { if (window) {
int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
@ -191,7 +191,7 @@ QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantM
window->property("width") window->property("width")
.toInt())); //*screen->devicePixelRatio()); when using manual scaler .toInt())); //*screen->devicePixelRatio()); when using manual scaler
window->setY(heightOffset - (*screenHeightOffset % heightOffset)); window->setY(heightOffset - (*screenHeightOffset % heightOffset));
qWarning() << window->geometry(); lDebug() << window->geometry();
} }
} }
}, },

View file

@ -66,6 +66,7 @@ bool AccountManager::login(QString username, QString password, QString *errorMes
} }
} }
username = Utils::getUsername(username);
identity->setUsername(Utils::appStringToCoreString(username)); identity->setUsername(Utils::appStringToCoreString(username));
if (params->setIdentityAddress(identity)) { if (params->setIdentityAddress(identity)) {
qWarning() << log() qWarning() << log()

View file

@ -94,4 +94,17 @@ void AccountModel::resetMissedCallsCount() {
mMonitor->resetMissedCallsCount(); mMonitor->resetMissedCallsCount();
emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/, emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/,
mMonitor->getMissedCallsCount()); // TODO mMonitor->getMissedCallsCount()); // TODO
}
void AccountModel::refreshUnreadNotifications() {
emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/,
mMonitor->getMissedCallsCount()); // TODO
}
int AccountModel::getMissedCallsCount() const {
return mMonitor->getMissedCallsCount();
}
int AccountModel::getUnreadMessagesCount() const {
return mMonitor->getUnreadChatMessageCount();
} }

View file

@ -44,6 +44,9 @@ public:
void setDefault(); void setDefault();
void removeAccount(); void removeAccount();
void resetMissedCallsCount(); void resetMissedCallsCount();
void refreshUnreadNotifications();
int getMissedCallsCount() const;
int getUnreadMessagesCount() const;
signals: signals:
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account, void registrationStateChanged(const std::shared_ptr<linphone::Account> &account,

View file

@ -141,11 +141,22 @@ void FriendModel::clearAddresses() {
} }
QString FriendModel::getName() const { QString FriendModel::getName() const {
return Utils::coreStringToAppString(mMonitor->getName()); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) {
created = mMonitor->createVcard(mMonitor->getName());
}
if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getName());
else return QString();
} }
void FriendModel::setName(const QString &name) { void FriendModel::setName(const QString &name) {
mMonitor->setName(Utils::appStringToCoreString(name)); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) {
created = mMonitor->createVcard(Utils::appStringToCoreString(name));
}
if (mMonitor->getVcard()) mMonitor->setName(Utils::appStringToCoreString(name));
} }
QString FriendModel::getGivenName() const { QString FriendModel::getGivenName() const {
@ -259,6 +270,11 @@ QString FriendModel::getPictureUri() const {
else return QString(); else return QString();
} }
QString FriendModel::getVCardAsString() const {
assert(mMonitor->getVcard());
return Utils::coreStringToAppString(mMonitor->getVcard()->asVcard4String());
}
void FriendModel::setPictureUri(const QString &uri) { void FriendModel::setPictureUri(const QString &uri) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto oldPictureUri = Utils::coreStringToAppString(mMonitor->getPhoto()); auto oldPictureUri = Utils::coreStringToAppString(mMonitor->getPhoto());

View file

@ -53,6 +53,7 @@ public:
bool getStarred() const; bool getStarred() const;
std::shared_ptr<linphone::Friend> getFriend() const; std::shared_ptr<linphone::Friend> getFriend() const;
QString getPictureUri() const; QString getPictureUri() const;
QString getVCardAsString() const;
protected: protected:
void setAddress(const std::shared_ptr<linphone::Address> &address); void setAddress(const std::shared_ptr<linphone::Address> &address);

View file

@ -62,6 +62,14 @@ VariantObject *Utils::getDisplayName(const QString &address) {
return data; return data;
} }
QString Utils::getUsername(const QString &address) {
QString res = address;
if (res.startsWith("sip:")) res.remove("sip:");
int splitIndex = res.lastIndexOf('@');
if (splitIndex != -1) res.truncate(splitIndex);
return res;
}
QString Utils::getGivenNameFromFullName(const QString &fullName) { QString Utils::getGivenNameFromFullName(const QString &fullName) {
if (fullName.isEmpty()) return QString(); if (fullName.isEmpty()) return QString();
auto nameSplitted = fullName.split(" "); auto nameSplitted = fullName.split(" ");

View file

@ -54,6 +54,7 @@ public:
} }
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address); Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
Q_INVOKABLE static QString getUsername(const QString &address);
Q_INVOKABLE static QString getGivenNameFromFullName(const QString &fullName); Q_INVOKABLE static QString getGivenNameFromFullName(const QString &fullName);
Q_INVOKABLE static QString getFamilyNameFromFullName(const QString &fullName); Q_INVOKABLE static QString getFamilyNameFromFullName(const QString &fullName);
Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32 Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32

View file

@ -31,6 +31,11 @@ Item {
contactPage.createContact(name, address) contactPage.createContact(name, address)
} }
AccountProxy {
id: accountProxy
onDefaultAccountChanged: if (tabbar.currentIndex === 0) defaultAccount.core.lResetMissedCalls()
}
Timer { Timer {
id: autoClosePopup id: autoClosePopup
interval: 5000 interval: 5000
@ -120,11 +125,13 @@ Item {
id: tabbar id: tabbar
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: 82 * DefaultStyle.dp Layout.preferredWidth: 82 * DefaultStyle.dp
defaultAccount: accountProxy.defaultAccount
property int unreadMessages: defaultAccount.core.unreadMessageNotifications
model: [ model: [
{icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels"), unreadNotifications: accountProxy.defaultAccount.core.unreadCallNotifications}, {icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")},
{icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts"), unreadNotifications: 0}, {icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts")},
{icon: AppIcons.chatTeardropText, selectedIcon: AppIcons.chatTeardropTextSelected, label: qsTr("Conversations"), unreadNotifications: accountProxy.defaultAccount.core.unreadMessageNotifications}, {icon: AppIcons.chatTeardropText, selectedIcon: AppIcons.chatTeardropTextSelected, label: qsTr("Conversations")},
{icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions"), unreadNotifications: 0} {icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions")}
] ]
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls() if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls()
@ -294,10 +301,6 @@ Item {
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
PopupButton { PopupButton {
id: avatarButton id: avatarButton
AccountProxy{
id: accountProxy
//property bool haveAvatar: defaultAccount && defaultAccount.core.pictureUri || false
}
background.visible: false background.visible: false
Layout.preferredWidth: 54 * DefaultStyle.dp Layout.preferredWidth: 54 * DefaultStyle.dp
Layout.preferredHeight: width Layout.preferredHeight: width
@ -312,6 +315,7 @@ Item {
popup.contentItem: ColumnLayout { popup.contentItem: ColumnLayout {
Accounts { Accounts {
id: accounts id: accounts
accountProxy: accountProxy
onAddAccountRequest: mainItem.addAccountRequest() onAddAccountRequest: mainItem.addAccountRequest()
} }
} }

View file

@ -15,6 +15,7 @@ Item {
readonly property int leftPadding: 32 * DefaultStyle.dp readonly property int leftPadding: 32 * DefaultStyle.dp
readonly property int rightPadding: 32 * DefaultStyle.dp readonly property int rightPadding: 32 * DefaultStyle.dp
readonly property int spacing: 16 * DefaultStyle.dp readonly property int spacing: 16 * DefaultStyle.dp
property AccountProxy accountProxy
signal addAccountRequest() signal addAccountRequest()
implicitHeight: list.contentHeight + topPadding + bottomPadding + 32 * DefaultStyle.dp + 1 + newAccountArea.height implicitHeight: list.contentHeight + topPadding + bottomPadding + 32 * DefaultStyle.dp + 1 + newAccountArea.height
@ -33,7 +34,7 @@ Item {
Layout.preferredHeight: contentHeight Layout.preferredHeight: contentHeight
Layout.fillWidth: true Layout.fillWidth: true
spacing: mainItem.spacing spacing: mainItem.spacing
model: AccountProxy{} model: mainItem.accountProxy
delegate: Contact{ delegate: Contact{
id: contactItem id: contactItem
width: list.width width: list.width

View file

@ -210,14 +210,14 @@ Item {
model: MagicSearchProxy { model: MagicSearchProxy {
searchText: searchBar.text.length === 0 ? "*" : searchBar.text searchText: searchBar.text.length === 0 ? "*" : searchBar.text
} }
onSelectedContactChanged: { onContactClicked: (contact) => {
if (selectedContact) { if (contact) {
if (selectedContact.core.allAddresses.length > 1) { if (contact.core.allAddresses.length > 1) {
startCallPopup.contact = selectedContact startCallPopup.contact = contact
startCallPopup.open() startCallPopup.open()
} else { } else {
mainItem.callButtonPressed(selectedContact.core.defaultAddress) mainItem.callButtonPressed(contact.core.defaultAddress)
} }
} }
} }

View file

@ -42,13 +42,14 @@ RowLayout {
id: videoButton id: videoButton
iconUrl: AppIcons.videoCamera iconUrl: AppIcons.videoCamera
checkedIconUrl: AppIcons.videoCameraSlash checkedIconUrl: AppIcons.videoCameraSlash
checked: !mainItem.localVideoEnabled
color: DefaultStyle.grey_500 color: DefaultStyle.grey_500
contentImageColor: DefaultStyle.main2_0 contentImageColor: DefaultStyle.main2_0
Layout.preferredWidth: 55 * DefaultStyle.dp Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp Layout.preferredHeight: 55 * DefaultStyle.dp
icon.width: 32 * DefaultStyle.dp icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
onCheckedChanged: mainItem.localVideoEnabled = !mainItem.localVideoEnabled onClicked: mainItem.localVideoEnabled = !mainItem.localVideoEnabled
} }
CheckableButton { CheckableButton {
id: microButton id: microButton

View file

@ -11,6 +11,7 @@ import UtilsCpp
Rectangle{ Rectangle{
id: mainItem id: mainItem
property AccountGui account property AccountGui account
signal avatarClicked() signal avatarClicked()
signal backgroundClicked() signal backgroundClicked()
@ -22,25 +23,27 @@ Rectangle{
RowLayout{ RowLayout{
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
Avatar{ RowLayout {
id: avatar spacing: 10 * DefaultStyle.dp
Layout.preferredWidth: 45 * DefaultStyle.dp Avatar{
Layout.preferredHeight: 45 * DefaultStyle.dp id: avatar
account: mainItem.account Layout.preferredWidth: 45 * DefaultStyle.dp
MouseArea{ Layout.preferredHeight: 45 * DefaultStyle.dp
anchors.fill: parent
onClicked: mainItem.avatarClicked()
}
}
Item {
Layout.preferredWidth: 200 * DefaultStyle.dp
Layout.fillHeight: true
Layout.leftMargin: 10 * DefaultStyle.dp
Layout.rightMargin: 10 * DefaultStyle.dp
ContactDescription{
id: description
anchors.fill: parent
account: mainItem.account account: mainItem.account
MouseArea{
anchors.fill: parent
onClicked: mainItem.avatarClicked()
}
}
Item {
Layout.preferredWidth: 200 * DefaultStyle.dp
Layout.fillHeight: true
Layout.rightMargin: 10 * DefaultStyle.dp
ContactDescription{
id: description
anchors.fill: parent
account: mainItem.account
}
} }
} }
Control.Control { Control.Control {
@ -96,20 +99,17 @@ Rectangle{
: qsTr("Erreur") : qsTr("Erreur")
} }
} }
// Item {
// Layout.fillWidth: true
// }
Item{ Item{
Layout.preferredWidth: 27 * DefaultStyle.dp Layout.preferredWidth: 26 * DefaultStyle.dp
Layout.preferredHeight: 27 * DefaultStyle.dp Layout.preferredHeight: 26 * DefaultStyle.dp
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 40 * DefaultStyle.dp
visible: mainItem.account.core.unreadCallNotifications > 0
Rectangle{ Rectangle{
id: unreadNotifications id: unreadNotifications
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
property int unread: mainItem.account.core.unreadNotifications width: 26 * DefaultStyle.dp
visible: unread > 0 height: 26 * DefaultStyle.dp
width: 27 * DefaultStyle.dp
height: 27 * DefaultStyle.dp
radius: width/2 radius: width/2
color: DefaultStyle.danger_500main color: DefaultStyle.danger_500main
border.color: DefaultStyle.grey_0 border.color: DefaultStyle.grey_0
@ -125,7 +125,7 @@ Rectangle{
fontSizeMode: Text.Fit fontSizeMode: Text.Fit
font.pixelSize: 11 * DefaultStyle.dp font.pixelSize: 11 * DefaultStyle.dp
font.weight: 700 * DefaultStyle.dp font.weight: 700 * DefaultStyle.dp
text: parent.unread > 100 ? '99+' : parent.unread text: mainItem.account.core.unreadCallNotifications >= 100 ? '99+' : mainItem.account.core.unreadCallNotifications
} }
} }
MultiEffect { MultiEffect {
@ -136,6 +136,7 @@ Rectangle{
shadowOpacity: 0.15 shadowOpacity: 0.15
} }
} }
Item{Layout.fillWidth: true}
EffectImage { EffectImage {
id: manageAccount id: manageAccount
imageSource: AppIcons.manageProfile imageSource: AppIcons.manageProfile

View file

@ -45,6 +45,7 @@ ListView {
signal contactStarredChanged() signal contactStarredChanged()
signal contactDeletionRequested(FriendGui contact) signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection() signal contactAddedToSelection()
signal contactClicked(FriendGui contact)
function addContactToSelection(address) { function addContactToSelection(address) {
if (multiSelectionEnabled) { if (multiSelectionEnabled) {
@ -112,7 +113,7 @@ ListView {
id: contactDelegate id: contactDelegate
anchors.left: initial.visible ? initial.right : parent.left anchors.left: initial.visible ? initial.right : parent.left
anchors.leftMargin: 10 * DefaultStyle.dp anchors.leftMargin: 10 * DefaultStyle.dp
anchors.right: parent.right anchors.right: actionsRow.left
// anchors.rightMargin: 10 * DefaultStyle.dp // anchors.rightMargin: 10 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
@ -182,7 +183,7 @@ ListView {
PopupButton { PopupButton {
id: friendPopup id: friendPopup
z: 1 z: 1
Layout.rightMargin: 5 * DefaultStyle.dp Layout.rightMargin: 13 * DefaultStyle.dp
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
popup.x: 0 popup.x: 0
popup.padding: 10 * DefaultStyle.dp popup.padding: 10 * DefaultStyle.dp
@ -249,8 +250,9 @@ ListView {
MouseArea { MouseArea {
id: contactArea id: contactArea
hoverEnabled: mainItem.hoverEnabled hoverEnabled: mainItem.hoverEnabled
anchors.fill: contactDelegate anchors.fill: itemDelegate
height: mainItem.height height: mainItem.height
z: -1
Rectangle { Rectangle {
anchors.fill: contactArea anchors.fill: contactArea
opacity: 0.7 opacity: 0.7
@ -259,6 +261,7 @@ ListView {
} }
onClicked: { onClicked: {
mainItem.currentIndex = index mainItem.currentIndex = index
mainItem.contactClicked(modelData)
if (mainItem.multiSelectionEnabled) { if (mainItem.multiSelectionEnabled) {
var indexInSelection = mainItem.selectedContacts.indexOf(modelData.core.defaultAddress) var indexInSelection = mainItem.selectedContacts.indexOf(modelData.core.defaultAddress)
if (indexInSelection == -1) { if (indexInSelection == -1) {

View file

@ -82,6 +82,7 @@ Item {
Text { Text {
id: waitingTime id: waitingTime
property int seconds property int seconds
visible: !UtilsCpp.isMe(mainItem.peerAddress)
text: UtilsCpp.formatElapsedTime(seconds) text: UtilsCpp.formatElapsedTime(seconds)
color: DefaultStyle.grey_0 color: DefaultStyle.grey_0
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter

View file

@ -8,52 +8,53 @@ import Qt.labs.platform 1.0
// ============================================================================= // =============================================================================
Window { Window {
id: mainItem id: mainItem
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
color: "transparent"
property bool requestActivate: false
//property int flags: Qt.SplashScreen property bool requestActivate: false
//property int flags: Qt.SplashScreen
default property alias _content: content.data default property alias _content: content.data
property bool _isOpen: false property bool _isOpen: false
signal isOpened() signal isOpened()
signal isClosed() signal isClosed()
signal dataChanged() signal dataChanged()
on_ContentChanged: dataChanged(_content) on_ContentChanged: dataChanged(_content)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function open () { function open () {
_isOpen = true; _isOpen = true;
isOpened(); isOpened();
} }
/* /*
function close () { function close () {
_isOpen = false _isOpen = false
isClosed() isClosed()
} }
*/ */
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
objectName: '__internalWindow' objectName: '__internalWindow'
property bool isFrameLess : false; property bool isFrameLess : false;
property bool showAsTool : false property bool showAsTool : false
// Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant // Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant
flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint; flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
opacity: 1.0 opacity: 1.0
height: _content[0] != null ? _content[0].height : 0 height: _content[0] != null ? _content[0].height : 0
width: _content[0] != null ? _content[0].width : 0 width: _content[0] != null ? _content[0].width : 0
visible:true visible:true
Item { Item {
id: content id: content
anchors.fill:parent anchors.fill:parent
property var $parent: mainItem property var $parent: mainItem
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/* /*

View file

@ -101,10 +101,12 @@ ColumnLayout {
target: LoginPageCpp target: LoginPageCpp
onRegistrationStateChanged: { onRegistrationStateChanged: {
if (LoginPageCpp.registrationState != LinphoneEnums.RegistrationState.Progress) { if (LoginPageCpp.registrationState != LinphoneEnums.RegistrationState.Progress) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0 connectionButtonContent.currentIndex = 0
} }
} }
onErrorMessageChanged: { onErrorMessageChanged: {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0 connectionButtonContent.currentIndex = 0
} }
} }
@ -123,6 +125,7 @@ ColumnLayout {
return return
} }
LoginPageCpp.login(usernameEdit.text, passwordEdit.text) LoginPageCpp.login(usernameEdit.text, passwordEdit.text)
connectionButton.enabled = false
connectionButtonContent.currentIndex = 1 connectionButtonContent.currentIndex = 1
} }

View file

@ -19,7 +19,7 @@ ListView {
spacing: 8 * DefaultStyle.dp spacing: 8 * DefaultStyle.dp
currentIndex: confInfoProxy.currentDateIndex currentIndex: confInfoProxy.currentDateIndex
onCountChanged: selectedConference = model && currentIndex != -1 ? model.getAt(currentIndex) : null onCountChanged: selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null
onCurrentIndexChanged: { onCurrentIndexChanged: {
selectedConference = model.getAt(currentIndex) selectedConference = model.getAt(currentIndex)
} }

View file

@ -1,17 +1,19 @@
import QtQuick 2.7 import QtQuick 2.7
import QtQuick.Effects
import Linphone import Linphone
// ============================================================================= // =============================================================================
DesktopPopup { DesktopPopup {
id: notification id: mainItem
property var notificationData: ({ property var notificationData: ({
timelineModel : null timelineModel : null
}) })
property int overriddenHeight property int overriddenHeight: 120 * DefaultStyle.dp
property int overriddenWidth property int overriddenWidth: 300 * DefaultStyle.dp
property double radius: 0
default property alias _content: content.data default property alias _content: content.data
signal deleteNotification (var notification) signal deleteNotification (var notification)
@ -29,13 +31,15 @@ DesktopPopup {
} }
Rectangle { Rectangle {
color: "#FFFFFF" id: background
height: overriddenHeight || 120 color: DefaultStyle.grey_0
width: overriddenWidth || 300 height: mainItem.overriddenHeight
width: mainItem.overriddenWidth
radius: mainItem.radius
border { border {
color: "#A1A1A1" color: DefaultStyle.grey_400
width: 1 width: 1 * DefaultStyle.dp
} }
Item { Item {
@ -55,4 +59,12 @@ DesktopPopup {
} }
} }
MultiEffect {
source: background
anchors.fill: background
shadowEnabled: true
shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1
shadowBlur: 1
}
} }

View file

@ -6,112 +6,95 @@ import UtilsCpp
Notification { Notification {
id: mainItem id: mainItem
radius: 20 * DefaultStyle.dp
// --------------------------------------------------------------------------- overriddenHeight: 101 * DefaultStyle.dp
overriddenWidth: 422 * DefaultStyle.dp
readonly property var call: notificationData && notificationData.call readonly property var call: notificationData && notificationData.call
property var state: call.core.state property var state: call.core.state
onStateChanged:{ onStateChanged:{
console.log("state notif", state, this) if (state != LinphoneEnums.CallState.IncomingReceived){
if(state != LinphoneEnums.CallState.IncomingReceived){
close() close()
} }
} }
// overridenWidth: 320 * DefaultStyle.dp
// overridenHeight: 150 * DefaultStyle.dp RowLayout {
// ---------------------------------------------------------------------------
ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 15 anchors.leftMargin: 19 * DefaultStyle.dp
anchors.rightMargin: 15 anchors.rightMargin: 19 * DefaultStyle.dp
anchors.bottomMargin:15 anchors.bottomMargin: 15 * DefaultStyle.dp
anchors.topMargin:15 anchors.topMargin: 15 * DefaultStyle.dp
spacing: 30 * DefaultStyle.dp
// ---------------------------------------------------------------------
// Action buttons.
// ---------------------------------------------------------------------
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
spacing: 15 * DefaultStyle.dp spacing: 13 * DefaultStyle.dp
Avatar { Avatar {
Layout.preferredWidth: 40 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 40 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
call: mainItem.call call: mainItem.call
} }
ColumnLayout { ColumnLayout {
Text { Text {
property var remoteAddress: UtilsCpp.getDisplayName(call.core.peerAddress) property var remoteAddress: UtilsCpp.getDisplayName(call.core.peerAddress)
text: remoteAddress ? remoteAddress.value : "" text: remoteAddress ? remoteAddress.value : ""
color: DefaultStyle.grey_600
font { font {
pixelSize: 14 * DefaultStyle.dp pixelSize: 20 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp weight: 800 * DefaultStyle.dp
capitalization: Font.Capitalize
} }
} }
Text { RowLayout {
text: call.core.peerAddress EffectImage {
imageSource: AppIcons.arrowDownLeft
colorizationColor: DefaultStyle.success_500main
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
}
Text {
Layout.fillWidth: true
elide: Text.ElideRight
property var localAddress: UtilsCpp.getDisplayName(call.core.localAddress)
text: qsTr("Appel entrant%1").arg(localAddress ? qsTr(" pour %1").arg(localAddress.value) : "") //call.core.peerAddress
color: DefaultStyle.grey_600
font {
pixelSize: 13 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
}
} }
} }
} }
RowLayout { RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
spacing: 10 * DefaultStyle.dp Layout.fillWidth: true
Item { spacing: 26 * DefaultStyle.dp
Layout.fillWidth: true Button {
Layout.fillHeight: true color: DefaultStyle.success_500main
} Layout.preferredWidth: 75 * DefaultStyle.dp
RowLayout { Layout.preferredHeight: 55 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter contentItem: EffectImage {
spacing: 3 * DefaultStyle.dp colorizationColor: DefaultStyle.grey_0
Button { imageSource: AppIcons.phone
color: DefaultStyle.success_500main imageWidth: 32 * DefaultStyle.dp
Layout.preferredWidth: 40 * DefaultStyle.dp imageHeight: 32 * DefaultStyle.dp
Layout.preferredHeight: 40 * DefaultStyle.dp
contentItem: EffectImage {
colorizationColor: DefaultStyle.grey_0
imageSource: AppIcons.phone
imageWidth: 24 * DefaultStyle.dp
imageHeight: 24 * DefaultStyle.dp
}
onClicked: {
mainItem.call.core.lAccept(false)
UtilsCpp.openCallsWindow(mainItem.call)
}
} }
Button { onClicked: {
color: DefaultStyle.success_500main mainItem.call.core.lAccept(false)
Layout.preferredWidth: 40 * DefaultStyle.dp UtilsCpp.openCallsWindow(mainItem.call)
Layout.preferredHeight: 40 * DefaultStyle.dp
contentItem: EffectImage {
colorizationColor: DefaultStyle.grey_0
imageSource: AppIcons.videoCamera
imageWidth: 24 * DefaultStyle.dp
imageHeight: 24 * DefaultStyle.dp
}
onClicked: {
mainItem.call.core.lAccept(true)
UtilsCpp.openCallsWindow(mainItem.call)
}
} }
} }
Item{
Layout.fillWidth: true
Layout.fillHeight: true
}
Button { Button {
color: DefaultStyle.danger_500main color: DefaultStyle.danger_500main
Layout.rightMargin: 20 * DefaultStyle.dp Layout.preferredWidth: 75 * DefaultStyle.dp
Layout.preferredWidth: 55 * DefaultStyle.dp Layout.preferredHeight: 55 * DefaultStyle.dp
Layout.preferredHeight: 40 * DefaultStyle.dp
contentItem: EffectImage { contentItem: EffectImage {
colorizationColor: DefaultStyle.grey_0 colorizationColor: DefaultStyle.grey_0
imageSource: AppIcons.endCall imageSource: AppIcons.endCall
imageWidth: 24 * DefaultStyle.dp imageWidth: 32 * DefaultStyle.dp
imageHeight: 24 * DefaultStyle.dp imageHeight: 32 * DefaultStyle.dp
} }
onClicked: { onClicked: {
mainItem.call.core.lDecline() mainItem.call.core.lDecline()

View file

@ -10,6 +10,7 @@ Control.TextField {
leftPadding: 15 * DefaultStyle.dp leftPadding: 15 * DefaultStyle.dp
rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp
echoMode: (hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal echoMode: (hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal
verticalAlignment: TextInput.AlignVCenter
color: DefaultStyle.main2_600 color: DefaultStyle.main2_600
font { font {
family: DefaultStyle.defaultFont family: DefaultStyle.defaultFont
@ -47,10 +48,12 @@ Control.TextField {
? DefaultStyle.main1_500_main ? DefaultStyle.main1_500_main
: mainItem.backgroundBorderColor : mainItem.backgroundBorderColor
} }
cursorDelegate: Rectangle { cursorDelegate: Rectangle {
id: cursor id: cursor
color: DefaultStyle.main1_500_main color: DefaultStyle.main1_500_main
width: 1 * DefaultStyle.dp width: 1 * DefaultStyle.dp
anchors.verticalCenter: mainItem.verticalCenter
SequentialAnimation { SequentialAnimation {
loops: Animation.Infinite loops: Animation.Infinite

View file

@ -13,6 +13,11 @@ Control.TabBar {
property var model property var model
readonly property alias cornerRadius: bottomLeftCorner.radius readonly property alias cornerRadius: bottomLeftCorner.radius
property AccountGui defaultAccount
onDefaultAccountChanged: {
defaultAccount.core.lRefreshNotifications()
}
component UnreadNotification: Rectangle { component UnreadNotification: Rectangle {
id: unreadNotifications id: unreadNotifications
property int unread: 0 property int unread: 0
@ -82,7 +87,7 @@ Control.TabBar {
width: mainItem.width width: mainItem.width
UnreadNotification { UnreadNotification {
unread: modelData.unreadNotifications unread: index == 0 ? defaultAccount.core.unreadCallNotifications : index == 2 ? defaultAccount.core.unreadMessageNotifications : 0// modelData.unreadNotifications
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 15 * DefaultStyle.dp anchors.rightMargin: 15 * DefaultStyle.dp
anchors.top: parent.top anchors.top: parent.top

View file

@ -549,7 +549,13 @@ AbstractMainPage {
iconSize: 24 * DefaultStyle.dp iconSize: 24 * DefaultStyle.dp
iconSource: AppIcons.shareNetwork iconSource: AppIcons.shareNetwork
text: qsTr("Share") text: qsTr("Share")
onClicked: console.log("TODO : share contact") onClicked: {
if (mainItem.selectedContact) {
var vcard = mainItem.selectedContact.core.getVCard()
UtilsCpp.copyToClipboard(vcard)
UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("VCard copiée dans le presse-papier"))
}
}
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true