mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-23 13:35:58 +03:00
Merge pull request #4102 from nextcloud/feature/file-names-in-activity
Show only filenames in tray activity items, with full path in tooltip
This commit is contained in:
commit
075f33a272
5 changed files with 122 additions and 69 deletions
|
@ -20,6 +20,10 @@ MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: (parent.containsMouse ? Style.lightHover : "transparent")
|
color: (parent.containsMouse ? Style.lightHover : "transparent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: containsMouse && displayLocation !== ""
|
||||||
|
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||||
|
ToolTip.text: qsTr("In %1").arg(displayLocation)
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: activityItem
|
id: activityItem
|
||||||
|
|
|
@ -61,11 +61,22 @@ public:
|
||||||
SyncFileItemType
|
SyncFileItemType
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RichSubjectParameter {
|
||||||
|
QString type; // Required
|
||||||
|
QString id; // Required
|
||||||
|
QString name; // Required
|
||||||
|
QString path; // Required (for files only)
|
||||||
|
QUrl link; // Optional (files only)
|
||||||
|
};
|
||||||
|
|
||||||
Type _type;
|
Type _type;
|
||||||
qlonglong _id;
|
qlonglong _id;
|
||||||
QString _fileAction;
|
QString _fileAction;
|
||||||
QString _objectType;
|
QString _objectType;
|
||||||
QString _subject;
|
QString _subject;
|
||||||
|
QString _subjectRich;
|
||||||
|
QHash<QString, RichSubjectParameter> _subjectRichParameters;
|
||||||
|
QString _subjectDisplay;
|
||||||
QString _message;
|
QString _message;
|
||||||
QString _folder;
|
QString _folder;
|
||||||
QString _file;
|
QString _file;
|
||||||
|
|
|
@ -58,6 +58,7 @@ QHash<int, QByteArray> ActivityListModel::roleNames() const
|
||||||
roles[DisplayPathRole] = "displayPath";
|
roles[DisplayPathRole] = "displayPath";
|
||||||
roles[PathRole] = "path";
|
roles[PathRole] = "path";
|
||||||
roles[AbsolutePathRole] = "absolutePath";
|
roles[AbsolutePathRole] = "absolutePath";
|
||||||
|
roles[DisplayLocationRole] = "displayLocation";
|
||||||
roles[LinkRole] = "link";
|
roles[LinkRole] = "link";
|
||||||
roles[MessageRole] = "message";
|
roles[MessageRole] = "message";
|
||||||
roles[ActionRole] = "type";
|
roles[ActionRole] = "type";
|
||||||
|
@ -114,15 +115,40 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
||||||
if (!ast && _accountState != ast.data())
|
if (!ast && _accountState != ast.data())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
switch (role) {
|
const auto getFilePath = [&]() {
|
||||||
case DisplayPathRole:
|
|
||||||
if (!a._file.isEmpty()) {
|
if (!a._file.isEmpty()) {
|
||||||
auto folder = FolderMan::instance()->folder(a._folder);
|
const auto folder = FolderMan::instance()->folder(a._folder);
|
||||||
QString relPath(a._file);
|
|
||||||
if (folder) {
|
const QString relPath = folder ? folder->remotePath() + a._file : a._file;
|
||||||
relPath.prepend(folder->remotePath());
|
|
||||||
}
|
|
||||||
const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
|
const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
|
||||||
|
|
||||||
|
if (localFiles.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is an E2EE file or folder, pretend we got no path, hiding the share button which is what we want
|
||||||
|
if (folder) {
|
||||||
|
SyncJournalFileRecord rec;
|
||||||
|
folder->journalDb()->getFileRecord(a._file.mid(1), &rec);
|
||||||
|
if (rec.isValid() && (rec._isE2eEncrypted || !rec._e2eMangledName.isEmpty())) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return localFiles.constFirst();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto getDisplayPath = [&a, &ast]() {
|
||||||
|
if (!a._file.isEmpty()) {
|
||||||
|
const auto folder = FolderMan::instance()->folder(a._folder);
|
||||||
|
|
||||||
|
QString relPath = folder ? folder->remotePath() + a._file : a._file;
|
||||||
|
|
||||||
|
const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
|
||||||
|
|
||||||
if (localFiles.count() > 0) {
|
if (localFiles.count() > 0) {
|
||||||
if (relPath.startsWith('/') || relPath.startsWith('\\')) {
|
if (relPath.startsWith('/') || relPath.startsWith('\\')) {
|
||||||
return relPath.remove(0, 1);
|
return relPath.remove(0, 1);
|
||||||
|
@ -132,54 +158,22 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto displayLocation = [&]() {
|
||||||
|
const auto displayPath = QFileInfo(getDisplayPath()).path();
|
||||||
|
return displayPath == "." || displayPath == "/" ? QString() : displayPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case DisplayPathRole:
|
||||||
|
return getDisplayPath();
|
||||||
case PathRole:
|
case PathRole:
|
||||||
if (!a._file.isEmpty()) {
|
return QUrl::fromLocalFile(QFileInfo(getFilePath()).path());
|
||||||
const auto folder = FolderMan::instance()->folder(a._folder);
|
case AbsolutePathRole:
|
||||||
|
return getFilePath();
|
||||||
QString relPath(a._file);
|
case DisplayLocationRole:
|
||||||
if (folder) {
|
return displayLocation();
|
||||||
relPath.prepend(folder->remotePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
// get relative path to the file so we can open it in the file manager
|
|
||||||
const auto localFiles = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
|
|
||||||
|
|
||||||
if (localFiles.isEmpty()) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an E2EE file or folder, pretend we got no path, this leads to
|
|
||||||
// hiding the share button which is what we want
|
|
||||||
if (folder) {
|
|
||||||
SyncJournalFileRecord rec;
|
|
||||||
folder->journalDb()->getFileRecord(a._file.mid(1), &rec);
|
|
||||||
if (rec.isValid() && (rec._isE2eEncrypted || !rec._e2eMangledName.isEmpty())) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUrl::fromLocalFile(localFiles.constFirst());
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
case AbsolutePathRole: {
|
|
||||||
const auto folder = FolderMan::instance()->folder(a._folder);
|
|
||||||
QString relPath(a._file);
|
|
||||||
if (!a._file.isEmpty()) {
|
|
||||||
if (folder) {
|
|
||||||
relPath.prepend(folder->remotePath());
|
|
||||||
}
|
|
||||||
const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
|
|
||||||
if (!localFiles.empty()) {
|
|
||||||
return localFiles.constFirst();
|
|
||||||
} else {
|
|
||||||
qWarning("File not local folders while processing absolute path request.");
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning("Received an absolute path request for an activity without a file path.");
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case ActionsLinksRole: {
|
case ActionsLinksRole: {
|
||||||
QList<QVariant> customList;
|
QList<QVariant> customList;
|
||||||
foreach (ActivityLink activityLink, a._links) {
|
foreach (ActivityLink activityLink, a._links) {
|
||||||
|
@ -242,7 +236,11 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ActionTextRole:
|
case ActionTextRole:
|
||||||
return a._subject;
|
if(a._subjectDisplay.isEmpty()) {
|
||||||
|
return a._subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a._subjectDisplay;
|
||||||
case ActionTextColorRole:
|
case ActionTextColorRole:
|
||||||
return a._id == -1 ? QLatin1String("#808080") : QLatin1String("#222"); // FIXME: This is a temporary workaround for _showMoreActivitiesAvailableEntry
|
return a._id == -1 ? QLatin1String("#808080") : QLatin1String("#222"); // FIXME: This is a temporary workaround for _showMoreActivitiesAvailableEntry
|
||||||
case MessageRole:
|
case MessageRole:
|
||||||
|
@ -332,16 +330,53 @@ void ActivityListModel::activitiesReceived(const QJsonDocument &json, int status
|
||||||
|
|
||||||
Activity a;
|
Activity a;
|
||||||
a._type = Activity::ActivityType;
|
a._type = Activity::ActivityType;
|
||||||
a._objectType = json.value("object_type").toString();
|
a._objectType = json.value(QStringLiteral("object_type")).toString();
|
||||||
a._accName = ast->account()->displayName();
|
a._accName = ast->account()->displayName();
|
||||||
a._id = json.value("activity_id").toInt();
|
a._id = json.value(QStringLiteral("activity_id")).toInt();
|
||||||
a._fileAction = json.value("type").toString();
|
a._fileAction = json.value(QStringLiteral("type")).toString();
|
||||||
a._subject = json.value("subject").toString();
|
a._subject = json.value(QStringLiteral("subject")).toString();
|
||||||
a._message = json.value("message").toString();
|
a._message = json.value(QStringLiteral("message")).toString();
|
||||||
a._file = json.value("object_name").toString();
|
a._file = json.value(QStringLiteral("object_name")).toString();
|
||||||
a._link = QUrl(json.value("link").toString());
|
a._link = QUrl(json.value(QStringLiteral("link")).toString());
|
||||||
a._dateTime = QDateTime::fromString(json.value("datetime").toString(), Qt::ISODate);
|
a._dateTime = QDateTime::fromString(json.value(QStringLiteral("datetime")).toString(), Qt::ISODate);
|
||||||
a._icon = json.value("icon").toString();
|
a._icon = json.value(QStringLiteral("icon")).toString();
|
||||||
|
|
||||||
|
auto richSubjectData = json.value(QStringLiteral("subject_rich")).toArray();
|
||||||
|
Q_ASSERT(richSubjectData.size() > 1);
|
||||||
|
|
||||||
|
if(richSubjectData.size() > 1) {
|
||||||
|
a._subjectRich = richSubjectData[0].toString();
|
||||||
|
auto parameters = richSubjectData[1].toObject();
|
||||||
|
const QRegularExpression subjectRichParameterRe(QStringLiteral("({[a-zA-Z0-9]*})"));
|
||||||
|
const QRegularExpression subjectRichParameterBracesRe(QStringLiteral("[{}]"));
|
||||||
|
|
||||||
|
for (auto i = parameters.begin(); i != parameters.end(); ++i) {
|
||||||
|
const auto parameterJsonObject = i.value().toObject();
|
||||||
|
const Activity::RichSubjectParameter parameter = {
|
||||||
|
parameterJsonObject.value(QStringLiteral("type")).toString(),
|
||||||
|
parameterJsonObject.value(QStringLiteral("id")).toString(),
|
||||||
|
parameterJsonObject.value(QStringLiteral("name")).toString(),
|
||||||
|
parameterJsonObject.contains(QStringLiteral("path")) ? parameterJsonObject.value(QStringLiteral("path")).toString() : QString(),
|
||||||
|
parameterJsonObject.contains(QStringLiteral("link")) ? QUrl(parameterJsonObject.value(QStringLiteral("link")).toString()) : QUrl(),
|
||||||
|
};
|
||||||
|
|
||||||
|
a._subjectRichParameters[i.key()] = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto displayString = a._subjectRich;
|
||||||
|
auto i = subjectRichParameterRe.globalMatch(displayString);
|
||||||
|
|
||||||
|
while (i.hasNext()) {
|
||||||
|
const auto match = i.next();
|
||||||
|
auto word = match.captured(1);
|
||||||
|
word.remove(subjectRichParameterBracesRe);
|
||||||
|
|
||||||
|
Q_ASSERT(a._subjectRichParameters.contains(word));
|
||||||
|
displayString = displayString.replace(match.captured(1), a._subjectRichParameters[word].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
a._subjectDisplay = displayString;
|
||||||
|
}
|
||||||
|
|
||||||
list.append(a);
|
list.append(a);
|
||||||
_currentItem = list.last()._id;
|
_currentItem = list.last()._id;
|
||||||
|
|
|
@ -55,6 +55,7 @@ public:
|
||||||
DisplayPathRole,
|
DisplayPathRole,
|
||||||
PathRole,
|
PathRole,
|
||||||
AbsolutePathRole,
|
AbsolutePathRole,
|
||||||
|
DisplayLocationRole, // Provides the display path to a file's parent folder, relative to Nextcloud root
|
||||||
LinkRole,
|
LinkRole,
|
||||||
PointInTimeRole,
|
PointInTimeRole,
|
||||||
AccountConnectedRole,
|
AccountConnectedRole,
|
||||||
|
|
|
@ -506,6 +506,8 @@ void User::processCompletedSyncItem(const Folder *folder, const SyncFileItemPtr
|
||||||
activity._folder = folder->alias();
|
activity._folder = folder->alias();
|
||||||
activity._fileAction = "";
|
activity._fileAction = "";
|
||||||
|
|
||||||
|
const auto fileName = QFileInfo(item->_originalFile).fileName();
|
||||||
|
|
||||||
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||||
activity._fileAction = "file_deleted";
|
activity._fileAction = "file_deleted";
|
||||||
} else if (item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
} else if (item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
||||||
|
@ -520,15 +522,15 @@ void User::processCompletedSyncItem(const Folder *folder, const SyncFileItemPtr
|
||||||
qCWarning(lcActivity) << "Item " << item->_file << " retrieved successfully.";
|
qCWarning(lcActivity) << "Item " << item->_file << " retrieved successfully.";
|
||||||
|
|
||||||
if (item->_direction != SyncFileItem::Up) {
|
if (item->_direction != SyncFileItem::Up) {
|
||||||
activity._message = tr("Synced %1").arg(item->_originalFile);
|
activity._message = tr("Synced %1").arg(fileName);
|
||||||
} else if (activity._fileAction == "file_renamed") {
|
} else if (activity._fileAction == "file_renamed") {
|
||||||
activity._message = tr("You renamed %1").arg(item->_originalFile);
|
activity._message = tr("You renamed %1").arg(fileName);
|
||||||
} else if (activity._fileAction == "file_deleted") {
|
} else if (activity._fileAction == "file_deleted") {
|
||||||
activity._message = tr("You deleted %1").arg(item->_originalFile);
|
activity._message = tr("You deleted %1").arg(fileName);
|
||||||
} else if (activity._fileAction == "file_created") {
|
} else if (activity._fileAction == "file_created") {
|
||||||
activity._message = tr("You created %1").arg(item->_originalFile);
|
activity._message = tr("You created %1").arg(fileName);
|
||||||
} else {
|
} else {
|
||||||
activity._message = tr("You changed %1").arg(item->_originalFile);
|
activity._message = tr("You changed %1").arg(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
_activityModel->addSyncFileItemToActivityList(activity);
|
_activityModel->addSyncFileItemToActivityList(activity);
|
||||||
|
|
Loading…
Reference in a new issue