mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-08-10 09:45:40 +02:00
chatview: display signaled back-end errors
A signal exists for showing errors to the user to make failing cases more explicit. With this patch, errors detected are displayed to the end user so that they know that an error occured and what kind of error occured. Change-Id: Ib2d4d4fdb171235e0598de0f1c190b8fd0fcc336
This commit is contained in:
parent
b0f3bc5572
commit
ce3afea995
14 changed files with 250 additions and 0 deletions
1
qml.qrc
1
qml.qrc
|
@ -98,6 +98,7 @@
|
|||
<file>src/app/mainview/components/SidePanel.qml</file>
|
||||
<file>src/app/mainview/components/WelcomePage.qml</file>
|
||||
<file>src/app/mainview/components/ChatView.qml</file>
|
||||
<file>src/app/mainview/components/ConversationErrorsRow.qml</file>
|
||||
<file>src/app/mainview/components/NewSwarmPage.qml</file>
|
||||
<file>src/app/mainview/components/ChatViewHeader.qml</file>
|
||||
<file>src/app/mainview/components/AccountComboBox.qml</file>
|
||||
|
|
|
@ -301,6 +301,7 @@ Item {
|
|||
property string placeVideoCall: qsTr("Place video call")
|
||||
property string showPlugins: qsTr("Show available plugins")
|
||||
property string addToConversations: qsTr("Add to conversations")
|
||||
property string backendError: qsTr("This is the error from the backend: %0")
|
||||
|
||||
// Chatview footer
|
||||
property string jumpToLatest: qsTr("Jump to latest")
|
||||
|
|
|
@ -495,6 +495,13 @@ ConversationsAdapter::updateConversationTitle(const QString& convId, const QStri
|
|||
convModel->updateConversationInfos(convId, details);
|
||||
}
|
||||
|
||||
void
|
||||
ConversationsAdapter::popFrontError(const QString& convId)
|
||||
{
|
||||
auto convModel = lrcInstance_->getCurrentConversationModel();
|
||||
convModel->popFrontError(convId);
|
||||
}
|
||||
|
||||
void
|
||||
ConversationsAdapter::updateConversationDescription(const QString& convId,
|
||||
const QString& newDescription)
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
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 popFrontError(const QString& convId);
|
||||
Q_INVOKABLE void updateConversationDescription(const QString& convId,
|
||||
const QString& newDescription);
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ CurrentConversation::updateData()
|
|||
} catch (...) {
|
||||
qWarning() << "Can't update current conversation data for" << convId;
|
||||
}
|
||||
updateErrors(convId);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -142,6 +143,11 @@ CurrentConversation::connectModel()
|
|||
this,
|
||||
&CurrentConversation::onProfileUpdated,
|
||||
Qt::UniqueConnection);
|
||||
connect(lrcInstance_->getCurrentConversationModel(),
|
||||
&ConversationModel::onConversationErrorsUpdated,
|
||||
this,
|
||||
&CurrentConversation::updateErrors,
|
||||
Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -149,3 +155,36 @@ CurrentConversation::showSwarmDetails() const
|
|||
{
|
||||
Q_EMIT showDetails();
|
||||
}
|
||||
|
||||
void
|
||||
CurrentConversation::updateErrors(const QString& convId)
|
||||
{
|
||||
if (convId != id_)
|
||||
return;
|
||||
try {
|
||||
const auto& convModel = lrcInstance_->getCurrentConversationModel();
|
||||
if (auto optConv = convModel->getConversationForUid(convId)) {
|
||||
auto& convInfo = optConv->get();
|
||||
QStringList newErrors;
|
||||
QStringList newBackendErr;
|
||||
for (const auto& [code, error]: convInfo.errors) {
|
||||
if (code == 1) {
|
||||
newErrors.append(tr("An error occurred while fetching this repository"));
|
||||
} else if (code == 2) {
|
||||
newErrors.append(tr("The conversation's mode is un-recognized"));
|
||||
} else if (code == 3) {
|
||||
newErrors.append(tr("An invalid message was detected"));
|
||||
} else if (code == 4) {
|
||||
newErrors.append(tr("Not enough authorization for updating conversation's infos"));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
newBackendErr.push_back(error);
|
||||
}
|
||||
set_backendErrors(newBackendErr);
|
||||
set_errors(newErrors);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ class CurrentConversation final : public QObject
|
|||
QML_PROPERTY(bool, isContact)
|
||||
QML_PROPERTY(bool, allMessagesLoaded)
|
||||
QML_PROPERTY(QString, modeString)
|
||||
QML_PROPERTY(QStringList, errors)
|
||||
QML_PROPERTY(QStringList, backendErrors)
|
||||
|
||||
public:
|
||||
explicit CurrentConversation(LRCInstance* lrcInstance, QObject* parent = nullptr);
|
||||
|
@ -62,6 +64,7 @@ private Q_SLOTS:
|
|||
void updateData();
|
||||
void onConversationUpdated(const QString& convId);
|
||||
void onProfileUpdated(const QString& convId);
|
||||
void updateErrors(const QString& convId);
|
||||
|
||||
private:
|
||||
LRCInstance* lrcInstance_;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
|
@ -104,6 +105,14 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
ConversationErrorsRow {
|
||||
id: errorRect
|
||||
color: JamiTheme.filterBadgeColor
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: JamiTheme.chatViewHeaderPreferredHeight
|
||||
visible: false
|
||||
}
|
||||
|
||||
SplitView {
|
||||
id: chatViewMainRow
|
||||
Layout.fillWidth: true
|
||||
|
|
102
src/app/mainview/components/ConversationErrorsRow.qml
Normal file
102
src/app/mainview/components/ConversationErrorsRow.qml
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Savoir-faire Linux Inc.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
import "../../commoncomponents"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
opacity: visible
|
||||
|
||||
Connections {
|
||||
target: CurrentConversation
|
||||
enabled: true
|
||||
|
||||
onErrorsChanged: {
|
||||
if (CurrentConversation.errors.length > 0) {
|
||||
errorLabel.text = CurrentConversation.errors[0]
|
||||
backendErrorToolTip.text = JamiStrings.backendError.arg(CurrentConversation.backendErrors[0])
|
||||
}
|
||||
errorRect.visible = CurrentConversation.errors.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: JamiTheme.preferredMarginSize
|
||||
|
||||
Text {
|
||||
id: errorLabel
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: CurrentConversation.errors.count > 0 ? CurrentConversation.errors[0][0] : ""
|
||||
color: JamiTheme.filterBadgeTextColor
|
||||
font.pixelSize: JamiTheme.headerFontSize
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
ResponsiveImage {
|
||||
id: backEndError
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
width: 30
|
||||
height: 30
|
||||
|
||||
source: JamiResources.outline_info_24dp_svg
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: JamiTheme.filterBadgeTextColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MaterialToolTip {
|
||||
id: backendErrorToolTip
|
||||
text: ""
|
||||
visible: parent.hovered && text !== ""
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
}
|
||||
}
|
||||
|
||||
PushButton {
|
||||
id: btnClose
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
|
||||
imageColor: JamiTheme.filterBadgeTextColor
|
||||
normalColor: JamiTheme.transparentColor
|
||||
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
|
||||
onClicked: ConversationsAdapter.popFrontError(CurrentConversation.id)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
from: 0
|
||||
duration: JamiTheme.shortFadeDuration
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ struct Info
|
|||
QString lastMessageUid = 0;
|
||||
QHash<QString, QString> parentsId; // pair messageid/parentid for messages without parent loaded
|
||||
unsigned int unreadMessages = 0;
|
||||
QVector<QPair<int, QString>> errors;
|
||||
|
||||
QSet<QString> typers;
|
||||
|
||||
|
|
|
@ -348,6 +348,11 @@ public:
|
|||
* @param info
|
||||
*/
|
||||
void updateConversationInfos(const QString& conversationId, MapStringString info);
|
||||
/**
|
||||
* Remove first error
|
||||
* @param conversationId
|
||||
*/
|
||||
void popFrontError(const QString& conversationId);
|
||||
|
||||
/**
|
||||
* @return if conversations requests exists.
|
||||
|
@ -427,6 +432,11 @@ Q_SIGNALS:
|
|||
* @param uid
|
||||
*/
|
||||
void conversationUpdated(const QString& uid) const;
|
||||
/**
|
||||
* Emitted when a conversation detects an error
|
||||
* @param uid
|
||||
*/
|
||||
void onConversationErrorsUpdated(const QString& uid) const;
|
||||
/**
|
||||
* Emitted when conversation's profile has been updated
|
||||
* @param uid
|
||||
|
|
|
@ -340,6 +340,11 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
|
|||
this,
|
||||
&CallbacksHandler::slotConversationMemberEvent,
|
||||
Qt::QueuedConnection);
|
||||
connect(&ConfigurationManager::instance(),
|
||||
&ConfigurationManagerInterface::conversationError,
|
||||
this,
|
||||
&CallbacksHandler::slotOnConversationError,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
CallbacksHandler::~CallbacksHandler() {}
|
||||
|
@ -791,4 +796,13 @@ CallbacksHandler::slotConversationMemberEvent(const QString& accountId,
|
|||
Q_EMIT conversationMemberEvent(accountId, conversationId, memberId, event);
|
||||
}
|
||||
|
||||
void
|
||||
CallbacksHandler::slotOnConversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what)
|
||||
{
|
||||
Q_EMIT conversationError(accountId, conversationId, code, what);
|
||||
}
|
||||
|
||||
} // namespace lrc
|
||||
|
|
|
@ -366,6 +366,10 @@ Q_SIGNALS:
|
|||
const QString& conversationId,
|
||||
const QString& memberId,
|
||||
int event);
|
||||
void conversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what);
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
|
@ -677,6 +681,10 @@ private Q_SLOTS:
|
|||
const QString& conversationId,
|
||||
const QString& memberId,
|
||||
int event);
|
||||
void slotOnConversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what);
|
||||
|
||||
private:
|
||||
const api::Lrc& parent;
|
||||
|
|
|
@ -369,6 +369,10 @@ public Q_SLOTS:
|
|||
const QString& conversationId,
|
||||
const QString& memberUri,
|
||||
int event);
|
||||
void slotOnConversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what);
|
||||
void slotConversationReady(const QString& accountId, const QString& conversationId);
|
||||
void slotConversationRemoved(const QString& accountId, const QString& conversationId);
|
||||
};
|
||||
|
@ -988,6 +992,18 @@ ConversationModel::updateConversationInfos(const QString& conversationId, const
|
|||
ConfigurationManager::instance().updateConversationInfos(owner.id, conversationId, newInfos);
|
||||
}
|
||||
|
||||
void
|
||||
ConversationModel::popFrontError(const QString& conversationId)
|
||||
{
|
||||
auto conversationOpt = getConversationForUid(conversationId);
|
||||
if (!conversationOpt.has_value())
|
||||
return;
|
||||
|
||||
auto& conversation = conversationOpt->get();
|
||||
conversation.errors.pop_front();
|
||||
Q_EMIT onConversationErrorsUpdated(conversationId);
|
||||
}
|
||||
|
||||
bool
|
||||
ConversationModel::hasPendingRequests() const
|
||||
{
|
||||
|
@ -1830,6 +1846,10 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
|
|||
&CallbacksHandler::conversationMemberEvent,
|
||||
this,
|
||||
&ConversationModelPimpl::slotConversationMemberEvent);
|
||||
connect(&callbacksHandler,
|
||||
&CallbacksHandler::conversationError,
|
||||
this,
|
||||
&ConversationModelPimpl::slotOnConversationError);
|
||||
}
|
||||
|
||||
ConversationModelPimpl::~ConversationModelPimpl()
|
||||
|
@ -1970,6 +1990,10 @@ ConversationModelPimpl::~ConversationModelPimpl()
|
|||
&CallbacksHandler::conversationMemberEvent,
|
||||
this,
|
||||
&ConversationModelPimpl::slotConversationMemberEvent);
|
||||
disconnect(&callbacksHandler,
|
||||
&CallbacksHandler::conversationError,
|
||||
this,
|
||||
&ConversationModelPimpl::slotOnConversationError);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2661,6 +2685,22 @@ ConversationModelPimpl::slotConversationMemberEvent(const QString& accountId,
|
|||
Q_EMIT linked.dataChanged(indexOf(conversationId));
|
||||
}
|
||||
|
||||
void
|
||||
ConversationModelPimpl::slotOnConversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what)
|
||||
{
|
||||
if (accountId != linked.owner.id || indexOf(conversationId) < 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto& conversation = getConversationForUid(conversationId).get();
|
||||
conversation.errors.push_back({code, what});
|
||||
Q_EMIT linked.onConversationErrorsUpdated(conversationId);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
void
|
||||
ConversationModelPimpl::slotIncomingContactRequest(const QString& contactUri)
|
||||
{
|
||||
|
|
|
@ -328,6 +328,16 @@ public:
|
|||
QString(conversationId.c_str()),
|
||||
QString(memberId.c_str()),
|
||||
event);
|
||||
}),
|
||||
exportable_callback<ConversationSignal::OnConversationError>(
|
||||
[this](const std::string& accountId,
|
||||
const std::string& conversationId,
|
||||
int code,
|
||||
const std::string& what) {
|
||||
Q_EMIT conversationError(QString(accountId.c_str()),
|
||||
QString(conversationId.c_str()),
|
||||
code,
|
||||
QString(what.c_str()));
|
||||
})};
|
||||
}
|
||||
|
||||
|
@ -1190,6 +1200,10 @@ Q_SIGNALS: // SIGNALS
|
|||
const QString& conversationId,
|
||||
const QString& memberId,
|
||||
int event);
|
||||
void conversationError(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
int code,
|
||||
const QString& what);
|
||||
};
|
||||
|
||||
namespace org {
|
||||
|
|
Loading…
Add table
Reference in a new issue