diff --git a/qml.qrc b/qml.qrc index 9dca240a..e3d6305b 100644 --- a/qml.qrc +++ b/qml.qrc @@ -94,6 +94,7 @@ src/mainview/components/SidePanel.qml src/mainview/components/WelcomePage.qml src/mainview/components/ChatView.qml + src/mainview/components/NewSwarmPage.qml src/mainview/components/ChatViewHeader.qml src/mainview/components/AccountComboBox.qml src/mainview/components/CallStackView.qml @@ -109,6 +110,7 @@ src/mainview/components/ConversationSmartListContextMenu.qml src/mainview/components/CallViewContextMenu.qml src/mainview/components/UserProfile.qml + src/mainview/components/SwarmDetailsPanel.qml src/mainview/components/SelectScreen.qml src/mainview/components/ScreenRubberBand.qml src/mainview/components/ContactPicker.qml diff --git a/resources/icons/swarm_details_panel.svg b/resources/icons/swarm_details_panel.svg new file mode 100644 index 00000000..2a302f23 --- /dev/null +++ b/resources/icons/swarm_details_panel.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml index d0db3dce..44196c6f 100644 --- a/src/constant/JamiStrings.qml +++ b/src/constant/JamiStrings.qml @@ -222,6 +222,7 @@ Item { property string resumeVideo: qsTr("Resume video") property string addParticipant: qsTr("Add participant") property string addParticipants: qsTr("Add participants") + property string details: qsTr("Details") property string chat: qsTr("Chat") property string moreOptions: qsTr("More options") property string mosaic: qsTr("Mosaic") @@ -609,4 +610,13 @@ Item { property string invitationViewJoinConversation: qsTr("Hello,\nWould you like to join the conversation?") property string invitationViewAcceptedConversation: qsTr("You have accepted\nthe conversation request") property string invitationViewWaitingForSync: qsTr("Waiting until %1\nconnects to synchronize the conversation.") + + // SwarmDetailsPanel + property string about: qsTr("About") + property string members: qsTr("Members") + property string documents: qsTr("Documents") + + // NewSwarmPage + + property string createTheSwarm: qsTr("Create the swarm") } diff --git a/src/contactadapter.cpp b/src/contactadapter.cpp index 534ba666..6ae89c87 100644 --- a/src/contactadapter.cpp +++ b/src/contactadapter.cpp @@ -55,7 +55,7 @@ ContactAdapter::getContactSelectableModel(int type) }); break; case SmartListModel::Type::ADDCONVMEMBER: - selectableProxyModel_->setPredicate([](const QModelIndex& index, const QRegExp&) { + selectableProxyModel_->setPredicate([](const QModelIndex& index, const QRegularExpression&) { return index.data(Role::IsCoreDialog).toBool(); }); break; @@ -108,7 +108,7 @@ ContactAdapter::setSearchFilter(const QString& filter) }); } else if (listModeltype_ == SmartListModel::Type::ADDCONVMEMBER) { selectableProxyModel_->setPredicate( - [this, filter](const QModelIndex& index, const QRegExp&) { + [this, filter](const QModelIndex& index, const QRegularExpression&) { return (index.data(Role::Title).toString().contains(filter, Qt::CaseInsensitive) || index.data(Role::RegisteredName) .toString() diff --git a/src/conversationsadapter.cpp b/src/conversationsadapter.cpp index 02786c58..5e87e005 100644 --- a/src/conversationsadapter.cpp +++ b/src/conversationsadapter.cpp @@ -480,6 +480,25 @@ ConversationsAdapter::restartConversation(const QString& convId) accInfo.contactModel->removeContact(peerUri); } +void +ConversationsAdapter::updateConversationTitle(const QString& convId, const QString& newTitle) +{ + auto convModel = lrcInstance_->getCurrentConversationModel(); + QMap details; + details["title"] = newTitle; + convModel->updateConversationInfo(convId, details); +} + +void +ConversationsAdapter::updateConversationDescription(const QString& convId, + const QString& newDescription) +{ + auto convModel = lrcInstance_->getCurrentConversationModel(); + QMap details; + details["description"] = newDescription; + convModel->updateConversationInfo(convId, details); +} + bool ConversationsAdapter::connectConversationModel() { diff --git a/src/conversationsadapter.h b/src/conversationsadapter.h index 72da591e..d9a7bc5d 100644 --- a/src/conversationsadapter.h +++ b/src/conversationsadapter.h @@ -52,6 +52,9 @@ public: Q_INVOKABLE void setFilter(const QString& filterString); Q_INVOKABLE QVariantMap getConvInfoMap(const QString& convId); Q_INVOKABLE void restartConversation(const QString& convId); + Q_INVOKABLE void updateConversationTitle(const QString& convId, const QString& newTitle); + Q_INVOKABLE void updateConversationDescription(const QString& convId, + const QString& newDescription); Q_SIGNALS: void showConversation(const QString& accountId, const QString& convUid); diff --git a/src/currentconversation.cpp b/src/currentconversation.cpp index 3a94d6fd..21ee8f43 100644 --- a/src/currentconversation.cpp +++ b/src/currentconversation.cpp @@ -51,6 +51,7 @@ CurrentConversation::updateData() if (auto optConv = accInfo.conversationModel->getConversationForUid(convId)) { auto& convInfo = optConv->get(); set_title(accInfo.conversationModel->title(convId)); + set_description(accInfo.conversationModel->description(convId)); set_uris(accInfo.conversationModel->peersForConversation(convId).toList()); set_isSwarm(convInfo.isSwarm()); set_isLegacy(convInfo.isLegacy()); diff --git a/src/currentconversation.h b/src/currentconversation.h index d57b5737..0ad13d40 100644 --- a/src/currentconversation.h +++ b/src/currentconversation.h @@ -31,6 +31,7 @@ class CurrentConversation final : public QObject Q_OBJECT QML_PROPERTY(QString, id) QML_PROPERTY(QString, title) + QML_PROPERTY(QString, description) QML_PROPERTY(QStringList, uris) QML_PROPERTY(bool, isSwarm) QML_PROPERTY(bool, isLegacy) diff --git a/src/mainview/MainView.qml b/src/mainview/MainView.qml index 0c119124..353ec1a0 100644 --- a/src/mainview/MainView.qml +++ b/src/mainview/MainView.qml @@ -80,6 +80,8 @@ Rectangle { if (isPageInStack("callStackViewObject", sidePanelViewStack) || isPageInStack("chatView", sidePanelViewStack) || isPageInStack("chatView", mainViewStack) || + isPageInStack("newSwarmPage", sidePanelViewStack) || + isPageInStack("newSwarmPage", mainViewStack) || isPageInStack("callStackViewObject", mainViewStack)) { sidePanelViewStack.pop(StackView.Immediate) mainViewStack.pop(welcomePage, StackView.Immediate) @@ -107,6 +109,16 @@ Rectangle { } } + function pushNewSwarmPage() { + if (sidePanelOnly) { + sidePanelViewStack.pop(StackView.Immediate) + sidePanelViewStack.push(newSwarmPage, StackView.Immediate) + } else { + mainViewStack.pop(welcomePage, StackView.Immediate) + mainViewStack.push(newSwarmPage, StackView.Immediate) + } + } + function startWizard() { mainViewStackLayout.currentIndex = 1 } @@ -353,6 +365,11 @@ Rectangle { function onNavigateToWelcomePageRequested() { backToMainView() } + + } + + onCreateSwarmClicked: { + pushNewSwarmPage() } } @@ -394,6 +411,18 @@ Rectangle { Component.onCompleted: MessagesAdapter.setQmlObject(this) } + NewSwarmPage { + id: newSwarmPage + + objectName: "newSwarmPage" + visible: false + + onCreateSwarmClicked: { + console.warn("@@@") + backToMainView() + } + } + onWidthChanged: { // Hide unnecessary stackview when width is changed. var widthToCompare = previousWidth < mainView.width ? diff --git a/src/mainview/components/ChatView.qml b/src/mainview/components/ChatView.qml index 2077ddcf..1ff47393 100644 --- a/src/mainview/components/ChatView.qml +++ b/src/mainview/components/ChatView.qml @@ -53,7 +53,7 @@ Rectangle { spacing: 0 ChatViewHeader { - id: messageWebViewHeader + id: chatViewHeader Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -76,6 +76,10 @@ Rectangle { root.needToHideConversationInCall() } + onShowDetailsClicked: { + swarmDetailsPanel.visible = !swarmDetailsPanel.visible + } + onPluginSelector: { // Create plugin handler picker - PLUGINS PluginHandlerPickerCreation.createPluginHandlerPickerObjects( @@ -86,22 +90,67 @@ Rectangle { } } - StackLayout { - id: chatViewStack - - Layout.alignment: Qt.AlignHCenter + RowLayout { + id: chatViewMainRow Layout.fillWidth: true - Layout.maximumWidth: JamiTheme.chatViewMaximumWidth Layout.fillHeight: true - Layout.topMargin: JamiTheme.chatViewHairLineSize - Layout.bottomMargin: JamiTheme.chatViewHairLineSize - currentIndex: CurrentConversation.isRequest || - CurrentConversation.needsSyncing + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true + + StackLayout { + id: chatViewStack + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumWidth: JamiTheme.chatViewMaximumWidth + Layout.topMargin: JamiTheme.chatViewHairLineSize + Layout.bottomMargin: JamiTheme.chatViewHairLineSize + + currentIndex: CurrentConversation.isRequest || + CurrentConversation.needsSyncing + + Loader { + active: CurrentConversation.id !== "" + sourceComponent: MessageListView { + DropArea { + anchors.fill: parent + onDropped: chatViewFooter.setFilePathsToSend(drop.urls) + } + } + } + + InvitationView { + id: invitationView + + Layout.fillWidth: true + Layout.fillHeight: true + } + } + + ReadOnlyFooter { + visible: CurrentConversation.readOnly + Layout.fillWidth: true + } + + ChatViewFooter { + id: chatViewFooter + + visible: { + if (CurrentConversation.needsSyncing || CurrentConversation.readOnly) + return false + else if (CurrentConversation.isSwarm && CurrentConversation.isRequest) + return false + return true + } + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + Layout.maximumHeight: JamiTheme.chatViewFooterMaximumHeight - Loader { - active: CurrentConversation.id !== "" - sourceComponent: MessageListView { DropArea { anchors.fill: parent onDropped: chatViewFooter.setFilePathsToSend(drop.urls) @@ -109,38 +158,11 @@ Rectangle { } } - InvitationView { - id: invitationView - - Layout.fillWidth: true + SwarmDetailsPanel { + id: swarmDetailsPanel + visible: false Layout.fillHeight: true - } - } - - ReadOnlyFooter { - visible: CurrentConversation.readOnly - Layout.fillWidth: true - } - - ChatViewFooter { - id: chatViewFooter - - visible: { - if (CurrentConversation.needsSyncing || CurrentConversation.readOnly) - return false - else if (CurrentConversation.isSwarm && CurrentConversation.isRequest) - return false - return true - } - - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.preferredHeight: implicitHeight - Layout.maximumHeight: JamiTheme.chatViewFooterMaximumHeight - - DropArea { - anchors.fill: parent - onDropped: chatViewFooter.setFilePathsToSend(drop.urls) + Layout.fillWidth: true } } } diff --git a/src/mainview/components/ChatViewHeader.qml b/src/mainview/components/ChatViewHeader.qml index 50053eea..ff0cdcd1 100644 --- a/src/mainview/components/ChatViewHeader.qml +++ b/src/mainview/components/ChatViewHeader.qml @@ -36,6 +36,7 @@ Rectangle { signal backClicked signal needToHideConversationInCall signal pluginSelector + signal showDetailsClicked property bool interactionButtonsVisibility: { if (CurrentConversation.inCall) @@ -51,6 +52,10 @@ Rectangle { } property bool addMemberVisibility: { + return swarmDetailsVisibility && !CurrentConversation.isRequest + } + + property bool swarmDetailsVisibility: { return !CurrentConversation.isCoreDialog && CurrentConversation.isSwarm } @@ -146,6 +151,7 @@ Rectangle { Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Layout.fillWidth: true Layout.rightMargin: 8 + spacing: 16 PushButton { id: startAAudioCallButton @@ -218,6 +224,20 @@ Rectangle { onClicked: MessagesAdapter.sendConversationRequest() } + + PushButton { + id: detailsButton + + visible: swarmDetailsVisibility + + source: JamiResources.swarm_details_panel_svg + toolTipText: JamiStrings.details + + normalColor: JamiTheme.chatviewBgColor + imageColor: JamiTheme.chatviewButtonColor + + onClicked: showDetailsClicked() + } } } diff --git a/src/mainview/components/NewSwarmPage.qml b/src/mainview/components/NewSwarmPage.qml new file mode 100644 index 00000000..7400e76b --- /dev/null +++ b/src/mainview/components/NewSwarmPage.qml @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Sébastien Blin + * + * 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 . + */ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import net.jami.Models 1.1 +import net.jami.Adapters 1.1 +import net.jami.Constants 1.1 + +import "../../commoncomponents" + + +Rectangle { + id: root + + color: JamiTheme.chatviewBgColor + + signal createSwarmClicked + + RowLayout { + id: mainLayout + + anchors.fill: parent + + MaterialButton { + id: btnCreateSwarm + + preferredWidth: JamiTheme.aboutButtonPreferredWidth + + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + color: JamiTheme.buttonTintedBlue + hoveredColor: JamiTheme.buttonTintedBlueHovered + pressedColor: JamiTheme.buttonTintedBluePressed + + text: JamiStrings.createTheSwarm + + onClicked: { + ConversationsAdapter.createSwarm() + createSwarmClicked() + } + } + } +} diff --git a/src/mainview/components/SidePanel.qml b/src/mainview/components/SidePanel.qml index f0ad5fcb..9fbe8d0e 100644 --- a/src/mainview/components/SidePanel.qml +++ b/src/mainview/components/SidePanel.qml @@ -31,6 +31,8 @@ Rectangle { color: JamiTheme.backgroundColor + signal createSwarmClicked + Connections { target: LRCInstance @@ -105,7 +107,7 @@ Rectangle { toolTipText: JamiStrings.startASwarm onClicked: { - ConversationsAdapter.createSwarm() + createSwarmClicked() } } } diff --git a/src/mainview/components/SwarmDetailsPanel.qml b/src/mainview/components/SwarmDetailsPanel.qml new file mode 100644 index 00000000..88468a79 --- /dev/null +++ b/src/mainview/components/SwarmDetailsPanel.qml @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Sébastien Blin + * + * 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 . + */ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import net.jami.Models 1.1 +import net.jami.Adapters 1.1 +import net.jami.Constants 1.1 + +import "../../commoncomponents" + +Rectangle { + id: root + + color: JamiTheme.buttonTintedBlue + + ColumnLayout { + id: swarmProfileDetails + Layout.fillWidth: true + Layout.fillHeight: true + + ConversationAvatar { + id: conversationAvatar + + Layout.alignment: Qt.AlignCenter + Layout.preferredWidth: JamiTheme.avatarSizeInCall + Layout.preferredHeight: JamiTheme.avatarSizeInCall + + imageId: LRCInstance.selectedConvUid + + showPresenceIndicator: false + } + + MaterialLineEdit { + Layout.alignment: Qt.AlignCenter + Layout.topMargin: JamiTheme.preferredMarginSize + + Layout.preferredWidth: root.width + + font.pointSize: JamiTheme.titleFontSize + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + text: CurrentConversation.title + color: "white" + + onEditingFinished: { + ConversationsAdapter.updateConversationTitle(LRCInstance.selectedConvUid, this.text) + } + } + + MaterialLineEdit { + Layout.alignment: Qt.AlignCenter + Layout.topMargin: JamiTheme.preferredMarginSize + + Layout.preferredWidth: root.width + + font.pointSize: JamiTheme.titleFontSize + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + text: CurrentConversation.description + color: "white" + + onEditingFinished: { + ConversationsAdapter.updateConversationDescription(LRCInstance.selectedConvUid, this.text) + } + } + + TabBar { + id: tabBar + + currentIndex: 1 + Layout.preferredWidth: root.width + + FilterTabButton { + id: aboutTabButton + + down: tabBar.currentIndex === 0 + labelText: JamiStrings.about + } + + FilterTabButton { + id: membersTabButton + + down: tabBar.currentIndex === 1 + labelText: JamiStrings.members + } + + FilterTabButton { + id: documentsTabButton + + down: tabBar.currentIndex === 2 + labelText: JamiStrings.documents + } + } + + + Rectangle { + Layout.alignment: Qt.AlignCenter + Layout.preferredWidth: root.width + Layout.preferredHeight: root.height + color: JamiTheme.secondaryBackgroundColor + } + } +}