diff --git a/Linphone/core/chat/ChatCore.cpp b/Linphone/core/chat/ChatCore.cpp index d54cf374..3ab8f878 100644 --- a/Linphone/core/chat/ChatCore.cpp +++ b/Linphone/core/chat/ChatCore.cpp @@ -89,6 +89,7 @@ ChatCore::ChatCore(const std::shared_ptr &chatRoom) : QObjec } resetChatMessageList(messageList); mIdentifier = Utils::coreStringToAppString(chatRoom->getIdentifier()); + mChatRoomState = LinphoneEnums::fromLinphone(chatRoom->getState()); connect(this, &ChatCore::messageListChanged, this, &ChatCore::lUpdateLastMessage); connect(this, &ChatCore::messagesInserted, this, &ChatCore::lUpdateLastMessage); connect(this, &ChatCore::messageRemoved, this, &ChatCore::lUpdateLastMessage); @@ -132,6 +133,12 @@ void ChatCore::setSelf(QSharedPointer me) { }); mChatModelConnection->makeConnectToModel( &ChatModel::deleted, [this]() { mChatModelConnection->invokeToCore([this]() { emit deleted(); }); }); + mChatModelConnection->makeConnectToModel( + &ChatModel::stateChanged, + [this](const std::shared_ptr &chatRoom, linphone::ChatRoom::State newState) { + auto state = LinphoneEnums::fromLinphone(newState); + mChatModelConnection->invokeToCore([this, state]() { setChatRoomState(state); }); + }); mChatModelConnection->makeConnectToModel(&ChatModel::chatMessageReceived, [this](const std::shared_ptr &chatRoom, @@ -277,6 +284,17 @@ LinphoneEnums::ChatMessageState ChatCore::getLastMessageState() const { return mLastMessage ? mLastMessage->getMessageState() : LinphoneEnums::ChatMessageState::StateIdle; } +LinphoneEnums::ChatRoomState ChatCore::getChatRoomState() const { + return mChatRoomState; +} + +void ChatCore::setChatRoomState(LinphoneEnums::ChatRoomState state) { + if (mChatRoomState != state) { + mChatRoomState = state; + emit chatRoomStateChanged(); + } +} + ChatMessageGui *ChatCore::getLastMessage() const { return mLastMessage ? new ChatMessageGui(mLastMessage) : nullptr; } diff --git a/Linphone/core/chat/ChatCore.hpp b/Linphone/core/chat/ChatCore.hpp index 8a6b22fd..c8deb39e 100644 --- a/Linphone/core/chat/ChatCore.hpp +++ b/Linphone/core/chat/ChatCore.hpp @@ -43,6 +43,7 @@ public: Q_PROPERTY(QString lastMessageText READ getLastMessageText NOTIFY lastMessageChanged) Q_PROPERTY(ChatMessageGui *lastMessage READ getLastMessage NOTIFY lastMessageChanged) Q_PROPERTY(LinphoneEnums::ChatMessageState lastMessageState READ getLastMessageState NOTIFY lastMessageChanged) + Q_PROPERTY(LinphoneEnums::ChatRoomState state READ getChatRoomState NOTIFY chatRoomStateChanged) Q_PROPERTY(int unreadMessagesCount READ getUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY unreadMessagesCountChanged) Q_PROPERTY(QString composingName READ getComposingName WRITE setComposingName NOTIFY composingUserChanged) @@ -70,6 +71,9 @@ public: LinphoneEnums::ChatMessageState getLastMessageState() const; + LinphoneEnums::ChatRoomState getChatRoomState() const; + void setChatRoomState(LinphoneEnums::ChatRoomState state); + QSharedPointer getLastMessageCore() const; void setLastMessage(QSharedPointer lastMessage); @@ -96,11 +100,9 @@ public: std::shared_ptr getModel() const; -Q_SIGNALS: +signals: // used to close all the notifications when one is clicked void messageOpen(); - -signals: void lastUpdatedTimeChanged(QDateTime time); void lastMessageChanged(); void titleChanged(QString title); @@ -111,6 +113,7 @@ signals: void avatarUriChanged(); void deleted(); void composingUserChanged(); + void chatRoomStateChanged(); void lDeleteMessage(); void lDelete(); @@ -134,6 +137,7 @@ private: QString mComposingName; QString mComposingAddress; bool mIsGroupChat = false; + LinphoneEnums::ChatRoomState mChatRoomState; std::shared_ptr mChatModel; QSharedPointer mLastMessage; QList> mChatMessageList; diff --git a/Linphone/core/chat/ChatList.cpp b/Linphone/core/chat/ChatList.cpp index bbf49d75..50f6ae1d 100644 --- a/Linphone/core/chat/ChatList.cpp +++ b/Linphone/core/chat/ChatList.cpp @@ -103,28 +103,6 @@ void ChatList::setSelf(QSharedPointer me) { }); }); - mModelConnection->makeConnectToModel( - &CoreModel::chatRoomStateChanged, - [this](const std::shared_ptr &core, const std::shared_ptr &chatRoom, - linphone::ChatRoom::State state) { - // check account, filter, then add if ok - if (chatRoom->getAccount() == core->getDefaultAccount()) { - if (state == linphone::ChatRoom::State::Created) { - auto list = getSharedList(); - auto found = - std::find_if(list.begin(), list.end(), [chatRoom](const QSharedPointer &item) { - return (item && item->getModel()->getMonitor() == chatRoom); - }); - if (found == list.end()) { - auto model = createChatCore(chatRoom); - mModelConnection->invokeToCore([this, model]() { - add(model); - emit chatAdded(); - }); - } - } - } - }); mModelConnection->makeConnectToModel( &CoreModel::defaultAccountChanged, [this](std::shared_ptr core, std::shared_ptr account) { lUpdate(); }); @@ -146,6 +124,19 @@ int ChatList::findChatIndex(ChatGui *chatGui) { return it == chatList.end() ? -1 : std::distance(chatList.begin(), it); } +void ChatList::addChatInList(ChatGui *chatGui) { + auto chatCore = chatGui->mCore; + auto chatList = getSharedList(); + auto it = std::find_if(chatList.begin(), chatList.end(), [chatCore](const QSharedPointer item) { + return item->getIdentifier() == chatCore->getIdentifier(); + }); + if (it == chatList.end()) { + connectItem(chatCore); + add(chatCore); + emit chatAdded(); + } +} + QVariant ChatList::data(const QModelIndex &index, int role) const { int row = index.row(); if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); diff --git a/Linphone/core/chat/ChatList.hpp b/Linphone/core/chat/ChatList.hpp index 15a52b35..3623b02f 100644 --- a/Linphone/core/chat/ChatList.hpp +++ b/Linphone/core/chat/ChatList.hpp @@ -42,6 +42,7 @@ public: void connectItem(QSharedPointer chat); int findChatIndex(ChatGui *chat); + void addChatInList(ChatGui *chatGui); virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; signals: diff --git a/Linphone/core/chat/ChatProxy.cpp b/Linphone/core/chat/ChatProxy.cpp index 98eccf02..12c16279 100644 --- a/Linphone/core/chat/ChatProxy.cpp +++ b/Linphone/core/chat/ChatProxy.cpp @@ -66,6 +66,13 @@ int ChatProxy::findChatIndex(ChatGui *chatGui) { return -1; } +void ChatProxy::addChatInList(ChatGui *chatGui) { + auto chatList = getListModel(); + if (chatList) { + chatList->addChatInList(chatGui); + } +} + bool ChatProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { // auto l = getItemAtSource(sourceRow); // return l != nullptr; diff --git a/Linphone/core/chat/ChatProxy.hpp b/Linphone/core/chat/ChatProxy.hpp index efb4dc2e..02a980ed 100644 --- a/Linphone/core/chat/ChatProxy.hpp +++ b/Linphone/core/chat/ChatProxy.hpp @@ -40,6 +40,7 @@ public: void setSourceModel(QAbstractItemModel *sourceModel) override; Q_INVOKABLE int findChatIndex(ChatGui *chatGui); + Q_INVOKABLE void addChatInList(ChatGui *chatGui); signals: void chatRemoved(ChatGui *chat); diff --git a/Linphone/model/tool/ToolModel.cpp b/Linphone/model/tool/ToolModel.cpp index f9bb8f86..da0069e9 100644 --- a/Linphone/model/tool/ToolModel.cpp +++ b/Linphone/model/tool/ToolModel.cpp @@ -467,11 +467,19 @@ QString ToolModel::computeUserAgent(const std::shared_ptr &con .remove("'"); } +bool ToolModel::isEndToEndEncryptedChatAvailable() { + auto core = CoreModel::getInstance()->getCore(); + auto defaultAccount = core->getDefaultAccount(); + return core->limeX3DhEnabled() && defaultAccount && !defaultAccount->getParams()->getLimeServerUrl().empty() && + !defaultAccount->getParams()->getConferenceFactoryUri().empty(); +} + std::shared_ptr ToolModel::getChatRoomParams(std::shared_ptr call, std::shared_ptr remoteAddress) { auto core = call ? call->getCore() : CoreModel::getInstance()->getCore(); auto localAddress = call ? call->getCallLog()->getLocalAddress() : nullptr; if (!remoteAddress && call) remoteAddress = call->getRemoteAddress()->clone(); + remoteAddress->clean(); auto account = findAccount(localAddress); if (!account) account = core->getDefaultAccount(); if (!account) qWarning() << "failed to get account, return"; @@ -481,7 +489,7 @@ ToolModel::getChatRoomParams(std::shared_ptr call, std::shared_p params->enableChat(true); params->enableGroup(false); //: Dummy subject - params->setSubject(Utils::appStringToCoreString(QObject::tr("chat_dummy_subject"))); + params->setSubject("Dummy subject"); params->setAccount(account); auto chatParams = params->getChatParams(); @@ -498,12 +506,12 @@ ToolModel::getChatRoomParams(std::shared_ptr call, std::shared_p chatParams->setBackend(linphone::ChatRoom::Backend::FlexisipChat); params->setSecurityLevel(linphone::Conference::SecurityLevel::EndToEnd); } else if (!accountParams->getInstantMessagingEncryptionMandatory()) { - if (SettingsModel::getInstance()->getCreateEndToEndEncryptedMeetingsAndGroupCalls()) { + if (isEndToEndEncryptedChatAvailable()) { qDebug() << "Account is in interop mode but LIME is available, requesting E2E encryption"; chatParams->setBackend(linphone::ChatRoom::Backend::FlexisipChat); params->setSecurityLevel(linphone::Conference::SecurityLevel::EndToEnd); } else { - qDebug() << "Account is in interop mode and LIME is available, disabling E2E encryption"; + qDebug() << "Account is in interop mode and LIME is not available, disabling E2E encryption"; chatParams->setBackend(linphone::ChatRoom::Backend::Basic); params->setSecurityLevel(linphone::Conference::SecurityLevel::None); } @@ -554,12 +562,14 @@ std::shared_ptr ToolModel::lookupChatForAddress(std::shared_ auto core = CoreModel::getInstance()->getCore(); auto account = core->getDefaultAccount(); if (!account) return nullptr; - auto localAddress = account->getParams()->getIdentityAddress(); + auto localAddress = account->getParams()->getIdentityAddress()->clone(); + localAddress->clean(); if (!localAddress || !remoteAddress) return nullptr; auto params = getChatRoomParams(nullptr, remoteAddress); std::list> participants; - participants.push_back(remoteAddress->clone()); + remoteAddress->clean(); + participants.push_back(remoteAddress); qDebug() << "Looking for chat with local address" << localAddress->asStringUriOnly() << "and participant" << remoteAddress->asStringUriOnly(); @@ -581,6 +591,33 @@ std::shared_ptr ToolModel::createChatForAddress(std::shared_ auto chatRoom = core->createChatRoom(params, participants); return chatRoom; } + +std::shared_ptr +ToolModel::createGroupChatRoom(QString subject, std::list> participantsAddresses) { + auto core = CoreModel::getInstance()->getCore(); + auto account = core->getDefaultAccount(); + + auto params = core->createConferenceParams(nullptr); + params->enableChat(true); + params->enableGroup(true); + params->setSubject(Utils::appStringToCoreString(subject)); + params->setAccount(account); + params->setSecurityLevel(linphone::Conference::SecurityLevel::EndToEnd); + + auto chatParams = params->getChatParams(); + if (!chatParams) { + qWarning() << "failed to get chat params from conference params, return"; + return nullptr; + } + chatParams->setEphemeralLifetime(0); + chatParams->setBackend(linphone::ChatRoom::Backend::FlexisipChat); + + auto accountParams = account->getParams(); + + auto chatRoom = core->createChatRoom(params, participantsAddresses); + return chatRoom; +} + // Presence mapping from SDK PresenceModel/RFC 3863 <-> Linphone UI (5 statuses Online, Offline, Away, Busy, DND). // Online = Basic Status open with no activity // Busy = Basic Status open with activity Busy and description busy @@ -589,11 +626,10 @@ std::shared_ptr ToolModel::createChatForAddress(std::shared_ // DND = Basic Status open with activity Other and description dnd // Note : close status on the last 2 items would be preferrable, but they currently trigger multiple tuple NOTIFY from // flexisip presence server Note 2 : close status with no activity triggers an unsubscribe. - LinphoneEnums::Presence ToolModel::corePresenceModelToAppPresence(std::shared_ptr presenceModel) { if (!presenceModel) { - lWarning() << sLog().arg("presence model is null."); + // lWarning() << sLog().arg("presence model is null."); return LinphoneEnums::Presence::Undefined; } diff --git a/Linphone/model/tool/ToolModel.hpp b/Linphone/model/tool/ToolModel.hpp index 02ddc64c..b180c366 100644 --- a/Linphone/model/tool/ToolModel.hpp +++ b/Linphone/model/tool/ToolModel.hpp @@ -85,8 +85,11 @@ public: getChatRoomParams(std::shared_ptr call, std::shared_ptr remoteAddress = nullptr); static std::shared_ptr lookupCurrentCallChat(std::shared_ptr callModel); static std::shared_ptr createCurrentCallChat(std::shared_ptr callModel); + static bool isEndToEndEncryptedChatAvailable(); static std::shared_ptr lookupChatForAddress(std::shared_ptr remoteAddress); static std::shared_ptr createChatForAddress(std::shared_ptr remoteAddress); + static std::shared_ptr + createGroupChatRoom(QString subject, std::list> participantsAddresses); static LinphoneEnums::Presence corePresenceModelToAppPresence(std::shared_ptr presenceModel); diff --git a/Linphone/tool/Constants.hpp b/Linphone/tool/Constants.hpp index b277a584..46cdc0f0 100644 --- a/Linphone/tool/Constants.hpp +++ b/Linphone/tool/Constants.hpp @@ -98,6 +98,7 @@ public: Q_PROPERTY(QString ContactUrl MEMBER ContactUrl CONSTANT) Q_PROPERTY(QString TranslationUrl MEMBER TranslationUrl CONSTANT) Q_PROPERTY(QString DefaultFont MEMBER DefaultFont CONSTANT) + Q_PROPERTY(QString DefaultLocale MEMBER DefaultLocale CONSTANT) Q_PROPERTY(int maxMosaicParticipants MEMBER MaxMosaicParticipants CONSTANT) Q_PROPERTY(QStringList reactionsList READ getReactionsList CONSTANT) diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index e3c4fe5e..aee851a5 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -1538,7 +1538,7 @@ VariantObject *Utils::getCurrentCallChat(CallGui *call) { data->mConnection->invokeToCore([] { //: Error showInformationPopup(tr("information_popup_error_title"), - //: Failed to create 1-1 conversation with %1 ! + //: Failed to create 1-1 conversation with %1 ! tr("information_popup_chatroom_creation_error_message"), false, getCallsWindow()); }); @@ -1556,6 +1556,7 @@ VariantObject *Utils::getChatForAddress(QString address) { data->makeRequest([address, data]() { auto linAddr = ToolModel::interpretUrl(address); if (!linAddr) return QVariant(); + linAddr->clean(); auto linphoneChatRoom = ToolModel::lookupChatForAddress(linAddr); if (linphoneChatRoom) { auto chatCore = ChatCore::create(linphoneChatRoom); @@ -1584,6 +1585,28 @@ VariantObject *Utils::getChatForAddress(QString address) { return data; } +VariantObject *Utils::createGroupChat(QString subject, QStringList participantAddresses) { + VariantObject *data = new VariantObject("lookupCurrentCallChat"); + if (!data) return nullptr; + data->makeRequest([subject, participantAddresses, data]() { + std::list> addresses; + for (auto &addr : participantAddresses) { + auto linAddr = ToolModel::interpretUrl(addr); + if (linAddr) addresses.push_back(linAddr); + else lWarning() << "Could not interpret address" << addr; + } + auto linphoneChatRoom = ToolModel::createGroupChatRoom(subject, addresses); + if (linphoneChatRoom) { + auto chatCore = ChatCore::create(linphoneChatRoom); + return QVariant::fromValue(new ChatGui(chatCore)); + } else { + return QVariant(); + } + }); + data->requestValue(); + return data; +} + void Utils::openChat(ChatGui *chat) { auto mainWindow = getMainWindow(); smartShowWindow(mainWindow); diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index c0b52659..f9697347 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -148,6 +148,7 @@ public: Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call); Q_INVOKABLE static VariantObject *getChatForAddress(QString address); + Q_INVOKABLE static VariantObject *createGroupChat(QString subject, QStringList participantAddresses); Q_INVOKABLE static void openChat(ChatGui *chat); Q_INVOKABLE static bool isEmptyMessage(QString message); Q_INVOKABLE static QString encodeTextToQmlRichFormat(const QString &text, diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 1ad677ed..1e30cdec 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -22,6 +22,8 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Control/Button/Settings/SwitchSetting.qml view/Control/Container/Carousel.qml + view/Control/Container/CreationFormLayout.qml + view/Control/Container/GroupCreationFormLayout.qml view/Control/Container/DetailLayout.qml view/Control/Container/FormItemLayout.qml view/Control/Container/ScrollBar.qml @@ -107,6 +109,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Control/Tool/Prototype/PhoneNumberPrototype.qml view/Page/Form/Call/NewCallForm.qml + view/Page/Form/Chat/NewChatForm.qml view/Page/Form/Chat/SelectedChatView.qml view/Page/Form/Contact/ContactDescription.qml view/Page/Form/Contact/ContactEdition.qml diff --git a/Linphone/view/Control/Container/CreationFormLayout.qml b/Linphone/view/Control/Container/CreationFormLayout.qml new file mode 100644 index 00000000..fa4e76da --- /dev/null +++ b/Linphone/view/Control/Container/CreationFormLayout.qml @@ -0,0 +1,109 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import QtQuick.Effects + +import Linphone +import UtilsCpp +import SettingsCpp + +FocusScope { + id: mainItem + property color searchBarColor: DefaultStyle.grey_100 + property color searchBarBorderColor: "transparent" + property alias searchBar: searchBar + property string startGroupButtonText + property NumericPadPopup numPadPopup + signal groupCreationRequested() + signal contactClicked(FriendGui contact) + clip: true + property alias topContent: topLayout.data + property bool topLayoutVisible: topLayout.children.length > 0 + + ColumnLayout { + anchors.fill: parent + spacing: Math.round(22 * DefaultStyle.dp) + ColumnLayout { + id: topLayout + visible: mainItem.topLayoutVisible + spacing: Math.round(18 * DefaultStyle.dp) + } + + ColumnLayout { + onVisibleChanged: if (!visible && mainItem.numPadPopup) mainItem.numPadPopup.close() + spacing: Math.round(38 * DefaultStyle.dp) + SearchBar { + id: searchBar + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + Layout.rightMargin: Math.round(39 * DefaultStyle.dp) + focus: true + color: mainItem.searchBarColor + borderColor: mainItem.searchBarBorderColor + //: "Rechercher un contact" + placeholderText: qsTr("search_bar_look_for_contact_text") + numericPadPopup: mainItem.numPadPopup + KeyNavigation.down: grouCreationButton + } + ColumnLayout { + id: content + spacing: Math.round(32 * DefaultStyle.dp) + Button { + id: grouCreationButton + Layout.preferredWidth: Math.round(320 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(44 * DefaultStyle.dp) + padding: 0 + KeyNavigation.up: searchBar + KeyNavigation.down: contactList + onClicked: mainItem.groupCreationRequested() + background: Rectangle { + anchors.fill: parent + radius: Math.round(50 * DefaultStyle.dp) + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: DefaultStyle.main2_100} + GradientStop { position: 1.0; color: DefaultStyle.grey_0} + } + } + contentItem: RowLayout { + spacing: Math.round(16 * DefaultStyle.dp) + anchors.verticalCenter: parent.verticalCenter + Image { + source: AppIcons.groupCall + Layout.preferredWidth: Math.round(44 * DefaultStyle.dp) + sourceSize.width: Math.round(44 * DefaultStyle.dp) + fillMode: Image.PreserveAspectFit + } + Text { + text: mainItem.startGroupButtonText + color: DefaultStyle.grey_1000 + font { + pixelSize: Typography.h4.pixelSize + weight: Typography.h4.weight + } + } + Item { + Layout.fillWidth: true + } + EffectImage { + imageSource: AppIcons.rightArrow + Layout.preferredWidth: Math.round(24 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) + colorizationColor: DefaultStyle.main2_500main + } + } + } + AllContactListView{ + id: contactList + Layout.fillWidth: true + Layout.fillHeight: true + showContactMenu: false + searchBarText: searchBar.text + onContactSelected: (contact) => { + mainItem.contactClicked(contact) + } + } + } + } + } +} diff --git a/Linphone/view/Control/Container/GroupCreationFormLayout.qml b/Linphone/view/Control/Container/GroupCreationFormLayout.qml new file mode 100644 index 00000000..5becd18b --- /dev/null +++ b/Linphone/view/Control/Container/GroupCreationFormLayout.qml @@ -0,0 +1,101 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import QtQuick.Effects + +import Linphone +import UtilsCpp +import SettingsCpp +import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle + +FocusScope { + id: mainItem + property alias addParticipantsLayout: addParticipantsLayout + property alias groupName: groupName + property string formTitle + property string createGroupButtonText + property int selectedParticipantsCount + signal returnRequested() + signal groupCreationRequested() + + ColumnLayout { + spacing: 0 + anchors.fill: parent + RowLayout { + spacing: Math.round(10 * DefaultStyle.dp) + Button { + id: backGroupCallButton + style: ButtonStyle.noBackgroundOrange + icon.source: AppIcons.leftArrow + Layout.preferredWidth: Math.round(24 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) + KeyNavigation.down: groupName + KeyNavigation.right: groupCallButton + KeyNavigation.left: groupCallButton + onClicked: { + mainItem.returnRequested() + } + } + Text { + text: mainItem.formTitle + color: DefaultStyle.main1_500_main + maximumLineCount: 1 + font { + pixelSize: Math.round(18 * DefaultStyle.dp) + weight: Typography.h4.weight + } + Layout.fillWidth: true + } + SmallButton { + id: groupCallButton + enabled: mainItem.selectedParticipantsCount.length != 0 + Layout.rightMargin: Math.round(21 * DefaultStyle.dp) + text: mainItem.createGroupButtonText + style: ButtonStyle.main + KeyNavigation.down: addParticipantsLayout + KeyNavigation.left: backGroupCallButton + KeyNavigation.right: backGroupCallButton + onClicked: { + mainItem.groupCreationRequested() + } + } + } + RowLayout { + spacing: 0 + Layout.topMargin: Math.round(18 * DefaultStyle.dp) + Layout.rightMargin: Math.round(38 * DefaultStyle.dp) + Text { + font.pixelSize: Typography.p2.pixelSize + font.weight: Typography.p2.weight + //: "Nom du groupe" + text: qsTr("history_group_call_start_dialog_subject_hint") + } + Item { + Layout.fillWidth: true + } + Text { + font.pixelSize: Math.round(12 * DefaultStyle.dp) + font.weight: Math.round(300 * DefaultStyle.dp) + //: "Requis" + text: qsTr("required") + } + } + TextField { + id: groupName + Layout.fillWidth: true + Layout.rightMargin: Math.round(38 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(49 * DefaultStyle.dp) + focus: true + KeyNavigation.down: addParticipantsLayout //participantList.count > 0 ? participantList : searchbar + } + AddParticipantsForm { + id: addParticipantsLayout + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: Math.round(15 * DefaultStyle.dp) + onSelectedParticipantsCountChanged: mainItem.selectedParticipantsCount = selectedParticipantsCount + focus: true + + } + } +} diff --git a/Linphone/view/Control/Display/Chat/ChatListView.qml b/Linphone/view/Control/Display/Chat/ChatListView.qml index 098b581b..a0fffcd6 100644 --- a/Linphone/view/Control/Display/Chat/ChatListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatListView.qml @@ -17,6 +17,9 @@ ListView { property string searchText: searchBar?.text property real busyIndicatorSize: Math.round(60 * DefaultStyle.dp) + property ChatGui currentChatGui + onCurrentIndexChanged: currentChatGui = model.getAt(currentIndex) || null + signal resultsReceived onResultsReceived: { @@ -43,6 +46,10 @@ ListView { mainItem.currentIndex = -1 mainItem.currentIndex = indexToSelect } + onLayoutChanged: { + var chatToSelect = getAt(mainItem.currentIndex) + selectChat(mainItem.currentChatGui) + } } // flickDeceleration: 10000 spacing: Math.round(10 * DefaultStyle.dp) @@ -50,6 +57,14 @@ ListView { function selectChat(chatGui) { var index = chatProxy.findChatIndex(chatGui) mainItem.currentIndex = index + // if the chat exists, it may not be displayed + // in list if hide_empty_chatrooms is set. Thus, we need + // to force adding it in the list so it is displayed + if (index === -1 && chatGui) { + chatProxy.addChatInList(chatGui) + var index = chatProxy.findChatIndex(chatGui) + mainItem.currentIndex = index + } } Component.onCompleted: cacheBuffer = Math.max(contentHeight, 0) //contentHeight>0 ? contentHeight : 0// cache all items @@ -67,9 +82,6 @@ ListView { chatProxy.displayMore() } } - onCountChanged: { - if (count > 0 && currentIndex < 0) currentIndex = 0 - } //---------------------------------------------------------------- function moveToCurrentItem() { diff --git a/Linphone/view/Control/Display/Contact/ContactListItem.qml b/Linphone/view/Control/Display/Contact/ContactListItem.qml index abfbee52..4019edda 100644 --- a/Linphone/view/Control/Display/Contact/ContactListItem.qml +++ b/Linphone/view/Control/Display/Contact/ContactListItem.qml @@ -4,7 +4,7 @@ import QtQuick.Controls.Basic as Control import Linphone import UtilsCpp 1.0 -import ConstantsCpp 1.0 +import ConstantsCpp import SettingsCpp import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle diff --git a/Linphone/view/Control/Popup/Notification/NotificationReceivedMessage.qml b/Linphone/view/Control/Popup/Notification/NotificationReceivedMessage.qml index 5d7ca4c6..139e23e3 100644 --- a/Linphone/view/Control/Popup/Notification/NotificationReceivedMessage.qml +++ b/Linphone/view/Control/Popup/Notification/NotificationReceivedMessage.qml @@ -25,7 +25,7 @@ Notification { property string message: notificationData ? notificationData.message : "" Connections { enabled: chat - target: chat.core + target: chat ? chat.core : null function onMessageOpen() { close() } diff --git a/Linphone/view/Page/Form/Call/NewCallForm.qml b/Linphone/view/Page/Form/Call/NewCallForm.qml index 99826d49..8af410ca 100644 --- a/Linphone/view/Page/Form/Call/NewCallForm.qml +++ b/Linphone/view/Page/Form/Call/NewCallForm.qml @@ -7,131 +7,43 @@ import Linphone import UtilsCpp import SettingsCpp -FocusScope { +CreationFormLayout { id: mainItem property bool groupCallVisible property bool displayCurrentCalls: false - property color searchBarColor: DefaultStyle.grey_100 - property color searchBarBorderColor: "transparent" - property alias searchBar: searchBar - property NumericPadPopup numPadPopup - signal callButtonPressed(string address) - signal groupCallCreationRequested() signal transferCallToAnotherRequested(CallGui dest) - signal contactClicked(FriendGui contact) - clip: true - ColumnLayout { - anchors.fill: parent - spacing: Math.round(22 * DefaultStyle.dp) - ColumnLayout { - spacing: Math.round(18 * DefaultStyle.dp) - visible: mainItem.displayCurrentCalls && callList.count > 0 - Text { - //: "Appels en cours" - text: qsTr("call_transfer_active_calls_label") - font { - pixelSize: Typography.h4.pixelSize - weight: Typography.h4.weight - } - } - Flickable { - Layout.fillWidth: true - Layout.preferredHeight: callListBackground.height - Layout.maximumHeight: mainItem.height/2 - contentHeight: callListBackground.height - contentWidth: width - RoundedPane { - id: callListBackground - anchors.left: parent.left - anchors.right: parent.right - contentItem: CallListView { - id: callList - isTransferList: true - onTransferCallToAnotherRequested: (dest) => { - mainItem.transferCallToAnotherRequested(dest) - } - } - } - } - } + //: Appel de groupe + startGroupButtonText: qsTr("call_start_group_call_title") - ColumnLayout { - onVisibleChanged: if (!visible) mainItem.numPadPopup.close() - spacing: Math.round(38 * DefaultStyle.dp) - SearchBar { - id: searchBar - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.rightMargin: Math.round(39 * DefaultStyle.dp) - focus: true - color: mainItem.searchBarColor - borderColor: mainItem.searchBarBorderColor - //: "Rechercher un contact" - placeholderText: qsTr("search_bar_look_for_contact_text") - numericPadPopup: mainItem.numPadPopup - KeyNavigation.down: grouCallButton + topLayoutVisible: mainItem.displayCurrentCalls && callList.count > 0 + topContent: [ + Text { + //: "Appels en cours" + text: qsTr("call_transfer_active_calls_label") + font { + pixelSize: Typography.h4.pixelSize + weight: Typography.h4.weight } - ColumnLayout { - id: content - spacing: Math.round(32 * DefaultStyle.dp) - Button { - id: grouCallButton - visible: mainItem.groupCallVisible && !SettingsCpp.disableMeetingsFeature - Layout.preferredWidth: Math.round(320 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(44 * DefaultStyle.dp) - padding: 0 - KeyNavigation.up: searchBar - KeyNavigation.down: contactList - onClicked: mainItem.groupCallCreationRequested() - background: Rectangle { - anchors.fill: parent - radius: Math.round(50 * DefaultStyle.dp) - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { position: 0.0; color: DefaultStyle.main2_100} - GradientStop { position: 1.0; color: DefaultStyle.grey_0} - } - } - contentItem: RowLayout { - spacing: Math.round(16 * DefaultStyle.dp) - anchors.verticalCenter: parent.verticalCenter - Image { - source: AppIcons.groupCall - Layout.preferredWidth: Math.round(44 * DefaultStyle.dp) - sourceSize.width: Math.round(44 * DefaultStyle.dp) - fillMode: Image.PreserveAspectFit - } - Text { - text: qsTr("call_start_group_call_title") - color: DefaultStyle.grey_1000 - font { - pixelSize: Typography.h4.pixelSize - weight: Typography.h4.weight - } - } - Item { - Layout.fillWidth: true - } - EffectImage { - imageSource: AppIcons.rightArrow - Layout.preferredWidth: Math.round(24 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) - colorizationColor: DefaultStyle.main2_500main - } - } - } - AllContactListView{ - id: contactList - Layout.fillWidth: true - Layout.fillHeight: true - showContactMenu: false - searchBarText: searchBar.text - onContactSelected: (contact) => { - mainItem.contactClicked(contact) + }, + Flickable { + Layout.fillWidth: true + Layout.preferredHeight: callListBackground.height + Layout.maximumHeight: mainItem.height/2 + contentHeight: callListBackground.height + contentWidth: width + RoundedPane { + id: callListBackground + anchors.left: parent.left + anchors.right: parent.right + contentItem: CallListView { + id: callList + isTransferList: true + onTransferCallToAnotherRequested: (dest) => { + mainItem.transferCallToAnotherRequested(dest) } } } } - } + ] } diff --git a/Linphone/view/Page/Form/Chat/GroupChatForm.qml b/Linphone/view/Page/Form/Chat/GroupChatForm.qml new file mode 100644 index 00000000..6a6facc5 --- /dev/null +++ b/Linphone/view/Page/Form/Chat/GroupChatForm.qml @@ -0,0 +1,15 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import QtQuick.Effects + +import Linphone +import UtilsCpp +import SettingsCpp + +CreationFormLayout { + id: mainItem + + //: Nouveau groupe + startGroupButtonText: qsTr("chat_start_group_chat_title") +} diff --git a/Linphone/view/Page/Form/Chat/NewChatForm.qml b/Linphone/view/Page/Form/Chat/NewChatForm.qml new file mode 100644 index 00000000..6a6facc5 --- /dev/null +++ b/Linphone/view/Page/Form/Chat/NewChatForm.qml @@ -0,0 +1,15 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import QtQuick.Effects + +import Linphone +import UtilsCpp +import SettingsCpp + +CreationFormLayout { + id: mainItem + + //: Nouveau groupe + startGroupButtonText: qsTr("chat_start_group_chat_title") +} diff --git a/Linphone/view/Page/Form/Meeting/AddParticipantsForm.qml b/Linphone/view/Page/Form/Meeting/AddParticipantsForm.qml index 27174160..5e579b31 100644 --- a/Linphone/view/Page/Form/Meeting/AddParticipantsForm.qml +++ b/Linphone/view/Page/Form/Meeting/AddParticipantsForm.qml @@ -25,52 +25,94 @@ FocusScope{ ColumnLayout { anchors.fill: parent spacing: Math.round(15 * DefaultStyle.dp) - ListView { + GridView { id: participantList Layout.fillWidth: true visible: contentHeight > 0 Layout.preferredHeight: contentHeight Layout.maximumHeight: mainItem.height / 3 width: mainItem.width + cellWidth: Math.round((50 + 18) * DefaultStyle.dp) + cellHeight: Math.round(80 * DefaultStyle.dp) + // columnCount: Math.floor(width/cellWidth) model: mainItem.selectedParticipants clip: true + // columnSpacing: Math.round(18 * DefaultStyle.dp) + // rowSpacing: Math.round(9 * DefaultStyle.dp) Keys.onPressed: (event) => { if(currentIndex <=0 && event.key == Qt.Key_Up){ nextItemInFocusChain(false).forceActiveFocus() } } + header: Text { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + visible: count > 0 + //: "%n participant(s) sélectionné(s)" + text: qsTr("add_participant_selected_count", '', count).arg(count) + maximumLineCount: 1 + color: DefaultStyle.grey_1000 + font { + pixelSize: Math.round(12 * DefaultStyle.dp) + weight: Math.round(300 * DefaultStyle.dp) + } + } delegate: FocusScope { - height: Math.round(56 * DefaultStyle.dp) - width: participantList.width - scrollbar.implicitWidth - Math.round(28 * DefaultStyle.dp) - RowLayout { + ColumnLayout { anchors.fill: parent - spacing: Math.round(10 * DefaultStyle.dp) - Avatar { - Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) - _address: modelData - shadowEnabled: false + spacing: Math.round(4 * DefaultStyle.dp) + width: Math.round(50 * DefaultStyle.dp) + Item { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: Math.round(50 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(50 * DefaultStyle.dp) + Avatar { + anchors.fill: parent + _address: modelData + shadowEnabled: false + } + Button { + Layout.preferredWidth: Math.round(17 * DefaultStyle.dp) + Layout.preferredHeight: Math.round(17 * DefaultStyle.dp) + icon.width: Math.round(12 * DefaultStyle.dp) + icon.height: Math.round(12 * DefaultStyle.dp) + icon.source: AppIcons.closeX + anchors.top: parent.top + anchors.right: parent.right + background: Item { + Rectangle { + id: backgroundRect + color: DefaultStyle.grey_0 + anchors.fill: parent + radius: Math.round(50 * DefaultStyle.dp) + } + MultiEffect { + anchors.fill: backgroundRect + source: backgroundRect + shadowEnabled: true + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 0.1 + shadowOpacity: 0.5 + } + } + onClicked: contactList.removeSelectedContactByAddress(modelData) + } } Text { - Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: width + width: Math.round(50 * DefaultStyle.dp) maximumLineCount: 1 + clip: true property var nameObj: UtilsCpp.getDisplayName(modelData) text: nameObj ? nameObj.value : "" - font.pixelSize: Math.round(14 * DefaultStyle.dp) - font.capitalization: Font.Capitalize - } - Item { - Layout.fillWidth: true - } - Button { - Layout.preferredWidth: Math.round(24 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) - style: ButtonStyle.noBackgroundOrange - icon.source: AppIcons.closeX - icon.width: Math.round(24 * DefaultStyle.dp) - icon.height: Math.round(24 * DefaultStyle.dp) - focus: true - onClicked: contactList.removeSelectedContactByAddress(modelData) + color: DefaultStyle.main2_700 + wrapMode: Text.WrapAnywhere + font { + pixelSize: Typography.p3.pixelSize + weight: Typography.p3.weight + capitalization: Font.Capitalize + } } } } diff --git a/Linphone/view/Page/Main/Call/CallPage.qml b/Linphone/view/Page/Main/Call/CallPage.qml index 0abde8bb..a25f1c9c 100644 --- a/Linphone/view/Page/Main/Call/CallPage.qml +++ b/Linphone/view/Page/Main/Call/CallPage.qml @@ -35,7 +35,6 @@ AbstractMainPage { property bool isRegistered: account ? account.core?.registrationState == LinphoneEnums.RegistrationState.Ok : false property int selectedParticipantsCount - signal startGroupCallRequested signal createCallFromSearchBarRequested signal createContactRequested(string name, string address) signal openNumPadRequest @@ -370,7 +369,7 @@ AbstractMainPage { onContactClicked: contact => { mainWindow.startCallWithContact(contact, false, callContactsList) } - onGroupCallCreationRequested: { + onGroupCreationRequested: { console.log("groupe call requetsed") listStackView.push(groupCallItem) } @@ -387,129 +386,30 @@ AbstractMainPage { Component { id: groupCallItem - FocusScope { + GroupCreationFormLayout { objectName: "groupCallItem" + //: "Appel de groupe" + formTitle: qsTr("call_start_group_call_title") + //: "Lancer" + createGroupButtonText: qsTr("call_action_start_group_call") Control.StackView.onActivated: { addParticipantsLayout.forceActiveFocus() } - ColumnLayout { - spacing: 0 - anchors.fill: parent - RowLayout { - spacing: Math.round(10 * DefaultStyle.dp) - visible: !SettingsCpp.disableMeetingsFeature - Button { - id: backGroupCallButton - style: ButtonStyle.noBackgroundOrange - icon.source: AppIcons.leftArrow - Layout.preferredWidth: Math.round(24 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) - KeyNavigation.down: listStackView - KeyNavigation.right: groupCallButton - KeyNavigation.left: groupCallButton - onClicked: { - listStackView.pop() - listStackView.currentItem?.forceActiveFocus() - } - } - ColumnLayout { - spacing: Math.round(3 * DefaultStyle.dp) - Text { - //: "Appel de groupe" - text: qsTr("call_start_group_call_title") - color: DefaultStyle.main1_500_main - maximumLineCount: 1 - font { - pixelSize: Math.round(18 * DefaultStyle.dp) - weight: Typography.h4.weight - } - Layout.fillWidth: true - } - Text { - //: "%n participant(s) sélectionné(s)" - text: qsTr("group_call_participant_selected", '', mainItem.selectedParticipantsCount).arg(mainItem.selectedParticipantsCount) - color: DefaultStyle.main2_500main - maximumLineCount: 1 - font { - pixelSize: Math.round(12 * DefaultStyle.dp) - weight: Math.round(300 * DefaultStyle.dp) - } - Layout.fillWidth: true - } - } - SmallButton { - id: groupCallButton - enabled: mainItem.selectedParticipantsCount.length != 0 - Layout.rightMargin: Math.round(21 * DefaultStyle.dp) - //: "Lancer" - text: qsTr("call_action_start_group_call") - style: ButtonStyle.main - KeyNavigation.down: listStackView - KeyNavigation.left: backGroupCallButton - KeyNavigation.right: backGroupCallButton - onClicked: { - mainItem.startGroupCallRequested() - } - } - } - RowLayout { - spacing: 0 - Layout.topMargin: Math.round(18 * DefaultStyle.dp) - Layout.rightMargin: Math.round(38 * DefaultStyle.dp) - Text { - font.pixelSize: Typography.p2.pixelSize - font.weight: Typography.p2.weight - //: "Nom du groupe" - text: qsTr("history_group_call_start_dialog_subject_hint") - } - Item { - Layout.fillWidth: true - } - Text { - font.pixelSize: Math.round(12 * DefaultStyle.dp) - font.weight: Math.round(300 * DefaultStyle.dp) - //: "Requis" - text: qsTr("required") - } - } - TextField { - id: groupCallName - Layout.fillWidth: true - Layout.rightMargin: Math.round(38 * DefaultStyle.dp) - Layout.preferredHeight: Math.round(49 * DefaultStyle.dp) - focus: true - KeyNavigation.down: addParticipantsLayout //participantList.count > 0 ? participantList : searchbar - } - AddParticipantsForm { - id: addParticipantsLayout - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: Math.round(15 * DefaultStyle.dp) - onSelectedParticipantsCountChanged: mainItem.selectedParticipantsCount = selectedParticipantsCount - focus: true - Connections { - target: mainItem - function onStartGroupCallRequested() { - if (groupCallName.text.length === 0) { - UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), - //: "Un nom doit être donné à l'appel de groupe - qsTr("group_call_error_must_have_name"), false) - } else if (!mainItem.isRegistered) { - UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), - //: "Vous n'etes pas connecté" - qsTr("group_call_error_not_connected"), false) - } else { - // mainItem.confInfoGui = Qt.createQmlObject( - // "import Linphone - // ConferenceInfoGui{}", mainItem) - // mainItem.confInfoGui.core.subject = groupCallName.text - // mainItem.confInfoGui.core.isScheduled = false - // mainItem.confInfoGui.core.addParticipants(addParticipantsLayout.selectedParticipants) - // mainItem.confInfoGui.core.save() - UtilsCpp.createGroupCall(groupCallName.text, addParticipantsLayout.selectedParticipants) - } - } - } + onReturnRequested: { + listStackView.pop() + listStackView.currentItem?.forceActiveFocus() + } + onGroupCreationRequested: { + if (groupName.text.length === 0) { + UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), + //: "Un nom doit être donné à l'appel de groupe + qsTr("group_call_error_must_have_name"), false) + } else if (!mainItem.isRegistered) { + UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), + //: "Vous n'etes pas connecté" + qsTr("group_call_error_not_connected"), false) + } else { + UtilsCpp.createGroupCall(groupName.text, addParticipantsLayout.selectedParticipants) } } } diff --git a/Linphone/view/Page/Main/Chat/ChatPage.qml b/Linphone/view/Page/Main/Chat/ChatPage.qml index ed0692b1..2c034074 100644 --- a/Linphone/view/Page/Main/Chat/ChatPage.qml +++ b/Linphone/view/Page/Main/Chat/ChatPage.qml @@ -16,24 +16,41 @@ AbstractMainPage { emptyListText: qsTr("chat_empty_title") newItemIconSource: AppIcons.plusCircle - property var selectedChatGui + property AccountProxy accounts: AccountProxy { + id: accountProxy + sourceModel: AppCpp.accounts + } + property AccountGui account: accountProxy.defaultAccount + property var state: account && account.core?.registrationState || 0 + property bool isRegistered: account ? account.core?.registrationState + == LinphoneEnums.RegistrationState.Ok : false + property var selectedChatGui property string remoteAddress onRemoteAddressChanged: console.log("ChatPage : remote address changed :", remoteAddress) property var remoteChatObj: UtilsCpp.getChatForAddress(remoteAddress) - property ChatGui remoteChat: remoteChatObj && remoteChatObj.value ? remoteChatObj.value : null - onRemoteChatChanged: if (remoteChat) selectedChatGui = remoteChat + property var remoteChat: remoteChatObj ? remoteChatObj.value : null + onRemoteChatChanged: { + selectedChatGui = remoteChat + } onSelectedChatGuiChanged: { - if (selectedChatGui) + if (selectedChatGui) { + if (!listStackView.currentItem || listStackView.currentItem.objectName !== "chatListItem") { + listStackView.popToIndex(0) + if (listStackView.depth === 0 || listStackView.currentItem.objectName !== "chatListItem") listStackView.push(chatListItem) + } rightPanelStackView.replace(currentChatComp, Control.StackView.Immediate) - else + } + else { rightPanelStackView.replace(emptySelection, Control.StackView.Immediate) + } } rightPanelStackView.initialItem: emptySelection + rightPanelStackView.visible: listStackView.currentItem && listStackView.currentItem.objectName === "chatListItem" onNoItemButtonPressed: goToNewChat() @@ -206,36 +223,79 @@ AbstractMainPage { //: "New chat" text: qsTr("chat_action_start_new_chat") color: DefaultStyle.main2_700 - font.pixelSize: Typography.h2.pixelSize - font.weight: Typography.h2.weight + font.pixelSize: Typography.h2m.pixelSize + font.weight: Typography.h2m.weight } Item { Layout.fillWidth: true } } - // NewCallForm { - // id: callContactsList - // Layout.topMargin: Math.round(18 * DefaultStyle.dp) - // Layout.fillWidth: true - // Layout.fillHeight: true - // focus: true - // numPadPopup: numericPadPopupItem - // groupCallVisible: true - // searchBarColor: DefaultStyle.grey_100 - // onContactClicked: contact => { - // mainWindow.startCallWithContact(contact, false, callContactsList) - // } - // onGroupCallCreationRequested: { - // console.log("groupe call requetsed") - // listStackView.push(groupCallItem) - // } - // Connections { - // target: mainItem - // function onCreateCallFromSearchBarRequested() { - // UtilsCpp.createCall(callContactsList.searchBar.text) - // } - // } - // } + NewChatForm { + id: newChatForm + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: Math.round(18 * DefaultStyle.dp) + onGroupCreationRequested: { + console.log("groupe call requetsed") + listStackView.push(groupChatItem) + } + onContactClicked: (contact) => { + if (contact) { + mainItem.remoteAddress = "" + mainItem.remoteAddress = contact.core.defaultAddress + } + } + } + } + } + } + + Component { + id: groupChatItem + GroupCreationFormLayout { + id: chatCreationLayout + + objectName: "groupChatItem" + //: "Nouveau groupe" + formTitle: qsTr("chat_start_group_chat_title") + //: "Créer" + createGroupButtonText: qsTr("chat_action_start_group_chat") + + property var groupChatObj + property var groupChat: groupChatObj ? groupChatObj.value : null + onGroupChatChanged: if (groupChat && groupChat.core.state === LinphoneEnums.ChatRoomState.Created) { + mainItem.selectedChatGui = groupChat + } + Connections { + enabled: groupChat || false + target: groupChat?.core || null + function onChatRoomStateChanged() { + if (chatCreationLayout.groupChat.core.state === LinphoneEnums.ChatRoomState.Created) { + mainItem.selectedChatGui = chatCreationLayout.groupChat + } + } + } + + Control.StackView.onActivated: { + addParticipantsLayout.forceActiveFocus() + } + onReturnRequested: { + listStackView.pop() + listStackView.currentItem?.forceActiveFocus() + } + onGroupCreationRequested: { + if (groupName.text.length === 0) { + UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), + //: "Un nom doit être donné au groupe + qsTr("group_chat_error_must_have_name"), false) + } else if (!mainItem.isRegistered) { + UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), + //: "Vous n'etes pas connecté" + qsTr("group_call_error_not_connected"), false) + } else { + console.log("create group chat") + chatCreationLayout.groupChatObj = UtilsCpp.createGroupChat(chatCreationLayout.groupName.text, addParticipantsLayout.selectedParticipants) + } } } } diff --git a/Linphone/view/Style/Typography.qml b/Linphone/view/Style/Typography.qml index ab887cb8..3c215ada 100644 --- a/Linphone/view/Style/Typography.qml +++ b/Linphone/view/Style/Typography.qml @@ -16,6 +16,13 @@ QtObject { pixelSize: Math.round(22 * DefaultStyle.dp), weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000) }) + + // Title/H2M - Large bloc title + property font h2m: Qt.font( { + family: DefaultStyle.defaultFont, + pixelSize: Math.round(20 * DefaultStyle.dp), + weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000) + }) // Title/H2 - Large bloc title property font h2: Qt.font( {