Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show received share information in share view #7373

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c62588b
Add displayFileOwner property to ShareModel
claucambra Oct 20, 2024
77c6dd6
Add fileOwnerDisplayName property to ShareModel
claucambra Oct 20, 2024
b687f1b
Set if the file owner should be displayed and the file owner display …
claucambra Oct 20, 2024
4fdac39
Add sharedWithMe-related properties to sharemodel
claucambra Oct 20, 2024
a72f23a
Also fetch shared with me share on target path
claucambra Oct 20, 2024
cf0dd27
When handling fetched shares, record shared-with-me related informati…
claucambra Oct 20, 2024
fce1304
Display file owner information (if not self) in share view
claucambra Oct 20, 2024
cf36ab9
Display shared with me file's share expiry in share view if relevant
claucambra Oct 20, 2024
aa7be97
Display share owner rather than file owner (this is more relevant to …
claucambra Oct 20, 2024
88a2904
Bolden string showing who owns the share that was shared with me
claucambra Oct 20, 2024
896e61a
Convert ImageProvider in an async image provider using an internal im…
claucambra Oct 20, 2024
d479c13
Add ability to fetch remote server avatars in usermodel avatar ImageR…
claucambra Oct 20, 2024
cec4970
Add shareOwnerAvatar property to ShareModel
claucambra Oct 20, 2024
7ff1d01
Build shareOwnerAvatar image provider string when handling sharedWith…
claucambra Oct 20, 2024
d7f7d94
Display image for sharedWithMe share owner in share view
claucambra Oct 20, 2024
1479371
Ensure requestedSize for avatars is valid
claucambra Oct 21, 2024
6610f2a
Ensure account pointer is valid when fetching avatars
claucambra Oct 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/gui/filedetails/ShareView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,34 @@ ColumnLayout {
}
}

RowLayout {
Layout.fillWidth: true
Layout.leftMargin: root.horizontalPadding
Layout.rightMargin: root.horizontalPadding

Image {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
source: shareModel.shareOwnerAvatar
}

ColumnLayout {
EnforcedPlainTextLabel {
Layout.fillWidth: true
visible: shareModel.displayShareOwner
text: qsTr("Shared with you by %1").arg(shareModel.shareOwnerDisplayName)
font.bold: true
}
EnforcedPlainTextLabel {
Layout.fillWidth: true
visible: shareModel.sharedWithMeExpires
text: qsTr("Expires in %1").arg(shareModel.sharedWithMeRemainingTimeString)
}
}

visible: shareModel.displayShareOwner
}

ShareeSearchField {
id: shareeSearchField
Layout.fillWidth: true
Expand Down
77 changes: 69 additions & 8 deletions src/gui/filedetails/sharemodel.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/filedetails/sharemodel.cpp

File src/gui/filedetails/sharemodel.cpp does not conform to Custom style guidelines. (lines 469, 499, 500, 501, 505, 506, 507, 514, 515, 516, 517, 1376, 1382, 1383)
* Copyright (C) 2022 by Claudio Cambra <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -219,12 +219,22 @@
_fetchOngoing = false;
_hasInitialShareFetchCompleted = false;
_sharees.clear();
_displayShareOwner = false;
_shareOwnerDisplayName.clear();
_shareOwnerAvatar.clear();
_sharedWithMeExpires = false;
_sharedWithMeRemainingTimeString.clear();

Q_EMIT sharePermissionsChanged();
Q_EMIT fetchOngoingChanged();
Q_EMIT hasInitialShareFetchCompletedChanged();
Q_EMIT shareesChanged();
Q_EMIT displayShareOwnerChanged();

Check warning on line 232 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:232:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
Q_EMIT shareOwnerDisplayNameChanged();

Check warning on line 233 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:233:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
Q_EMIT shareOwnerAvatarChanged();

Check warning on line 234 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:234:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
Q_EMIT sharedWithMeExpiresChanged();

Check warning on line 235 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:235:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
Q_EMIT sharedWithMeRemainingTimeStringChanged();

Check warning on line 236 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:236:12 [modernize-use-trailing-return-type]

use a trailing return type for this function

Check warning on line 237 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:237:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
endResetModel();
}

Expand Down Expand Up @@ -318,7 +328,9 @@
auto job = new PropfindJob(_accountState->account(), _sharePath);
job->setProperties(QList<QByteArray>() << "http://open-collaboration-services.org/ns:share-permissions"
<< "http://owncloud.org/ns:fileid" // numeric file id for fallback private link generation
<< "http://owncloud.org/ns:privatelink");
<< "http://owncloud.org/ns:privatelink"
<< "http://owncloud.org/ns:owner-id"
<< "http://owncloud.org/ns:owner-display-name");
job->setTimeout(10 * 1000);
connect(job, &PropfindJob::result, this, &ShareModel::slotPropfindReceived);
connect(job, &PropfindJob::finishedWithError, this, [&](const QNetworkReply *reply) {
Expand Down Expand Up @@ -454,7 +466,7 @@

const auto privateLinkUrl = result["privatelink"].toString();
_fileRemoteId = result["fileid"].toByteArray();

if (!privateLinkUrl.isEmpty()) {
qCInfo(lcShareModel) << "Received private link url for" << _sharePath << privateLinkUrl;
_privateLinkUrl = privateLinkUrl;
Expand All @@ -476,14 +488,38 @@
qCInfo(lcSharing) << "Fetched" << shares.count() << "shares";

for (const auto &share : shares) {
if (share.isNull() ||
share->account().isNull() ||
share->getUidOwner() != share->account()->davUser()) {

if (share.isNull()) {
continue;
} else if (const auto selfUserId = share->account()->davUser(); share->getUidOwner() != selfUserId) {
_displayShareOwner = true;
Q_EMIT displayShareOwnerChanged();
_shareOwnerDisplayName = share->getOwnerDisplayName();
Q_EMIT shareOwnerDisplayNameChanged();
_shareOwnerAvatar = "image://avatars/user-id="
+ share->getUidOwner()
+ "/local-account:"
+ share->account()->displayName();
Q_EMIT shareOwnerAvatarChanged();

if (share->getShareType() == Share::TypeUser &&
share->getShareWith() &&
share->getShareWith()->shareWith() == selfUserId)
{
const auto userShare = share.objectCast<UserGroupShare>();
const auto expireDate = userShare->getExpireDate();
const auto daysToExpire = QDate::currentDate().daysTo(expireDate);
_sharedWithMeExpires = expireDate.isValid();
Q_EMIT sharedWithMeExpiresChanged();
_sharedWithMeRemainingTimeString = daysToExpire > 1
? tr("%1 days").arg(daysToExpire)
: daysToExpire > 0
? tr("1 day")
: tr("Today");
Q_EMIT sharedWithMeRemainingTimeStringChanged();
}
} else {
slotAddShare(share);
}

slotAddShare(share);
}

handleLinkShare();
Expand Down Expand Up @@ -1326,6 +1362,31 @@
return _isShareDisabledEncryptedFolder;
}

bool ShareModel::displayShareOwner() const
{
return _displayShareOwner;
}

Check warning on line 1368 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:1368:18 [modernize-use-trailing-return-type]

use a trailing return type for this function

QString ShareModel::shareOwnerDisplayName() const
{
return _shareOwnerDisplayName;
}

Check warning on line 1374 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:1374:18 [modernize-use-trailing-return-type]

use a trailing return type for this function
QString ShareModel::shareOwnerAvatar() const
{
return _shareOwnerAvatar;
}

QString ShareModel::sharedWithMeRemainingTimeString() const

Check warning on line 1380 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:1380:18 [modernize-use-trailing-return-type]

use a trailing return type for this function
{
return _sharedWithMeRemainingTimeString;
}

bool ShareModel::sharedWithMeExpires() const
{
return _sharedWithMeExpires;

Check warning on line 1387 in src/gui/filedetails/sharemodel.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.cpp:1387:18 [modernize-use-trailing-return-type]

use a trailing return type for this function
}

QVariantList ShareModel::sharees() const
{
QVariantList returnSharees;
Expand Down
21 changes: 21 additions & 0 deletions src/gui/filedetails/sharemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#pragma once

#include <QAbstractListModel>

Check failure on line 17 in src/gui/filedetails/sharemodel.h

View workflow job for this annotation

GitHub Actions / build

src/gui/filedetails/sharemodel.h:17:10 [clang-diagnostic-error]

'QAbstractListModel' file not found

#include "accountstate.h"
#include "folder.h"
Expand All @@ -38,6 +38,11 @@
Q_PROPERTY(bool hasInitialShareFetchCompleted READ hasInitialShareFetchCompleted NOTIFY hasInitialShareFetchCompletedChanged)
Q_PROPERTY(bool serverAllowsResharing READ serverAllowsResharing NOTIFY serverAllowsResharingChanged)
Q_PROPERTY(QVariantList sharees READ sharees NOTIFY shareesChanged)
Q_PROPERTY(bool displayShareOwner READ displayShareOwner NOTIFY displayShareOwnerChanged)
Q_PROPERTY(QString shareOwnerDisplayName READ shareOwnerDisplayName NOTIFY shareOwnerDisplayNameChanged)
Q_PROPERTY(QString shareOwnerAvatar READ shareOwnerAvatar NOTIFY shareOwnerAvatarChanged)
Q_PROPERTY(bool sharedWithMeExpires READ sharedWithMeExpires NOTIFY sharedWithMeExpiresChanged)
Q_PROPERTY(QString sharedWithMeRemainingTimeString READ sharedWithMeRemainingTimeString NOTIFY sharedWithMeRemainingTimeStringChanged)

public:
enum Roles {
Expand Down Expand Up @@ -126,6 +131,12 @@

[[nodiscard]] QVariantList sharees() const;

[[nodiscard]] bool displayShareOwner() const;
[[nodiscard]] QString shareOwnerDisplayName() const;
[[nodiscard]] QString shareOwnerAvatar() const;
[[nodiscard]] bool sharedWithMeExpires() const;
[[nodiscard]] QString sharedWithMeRemainingTimeString() const;

[[nodiscard]] Q_INVOKABLE static QString generatePassword();

signals:
Expand All @@ -143,6 +154,11 @@
void shareesChanged();
void internalLinkReady();
void serverAllowsResharingChanged();
void displayShareOwnerChanged();
void shareOwnerDisplayNameChanged();
void shareOwnerAvatarChanged();
void sharedWithMeExpiresChanged();
void sharedWithMeRemainingTimeStringChanged();

void serverError(const int code, const QString &message) const;
void passwordSetError(const QString &shareId, const int code, const QString &message);
Expand Down Expand Up @@ -246,6 +262,11 @@
SyncJournalFileLockInfo _filelockState;
QString _privateLinkUrl;
QByteArray _fileRemoteId;
bool _displayShareOwner = false;
QString _shareOwnerDisplayName;
QString _shareOwnerAvatar;
bool _sharedWithMeExpires = false;
QString _sharedWithMeRemainingTimeString;

QSharedPointer<ShareManager> _manager;

Expand Down
1 change: 1 addition & 0 deletions src/gui/ocssharejob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void OcsShareJob::getShares(const QString &path, const QMap<QString, QString> &p

addParam(QString::fromLatin1("path"), path);
addParam(QString::fromLatin1("reshares"), QString("true"));
addParam("shared_with_me", "true");

for (auto it = std::cbegin(params); it != std::cend(params); ++it) {
addParam(it.key(), it.value());
Expand Down
84 changes: 62 additions & 22 deletions src/gui/tray/usermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,35 +1613,74 @@ int UserModel::findUserIdForAccount(AccountState *account) const
}
/*-------------------------------------------------------------------------------------*/

ImageProvider::ImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
{
}
class ImageResponse : public QQuickImageResponse
{
public:
ImageResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool)
{
Q_UNUSED(pool)

const auto makeIcon = [](const QString &path) {
QImage image(128, 128, QImage::Format_ARGB32);
image.fill(Qt::GlobalColor::transparent);
QPainter painter(&image);
QSvgRenderer renderer(path);
renderer.render(&painter);
return image;
};

if (id == QLatin1String("fallbackWhite")) {
handleDone(makeIcon(QStringLiteral(":/client/theme/white/user.svg")));
return;
} else if (id == QLatin1String("fallbackBlack")) {
handleDone(makeIcon(QStringLiteral(":/client/theme/black/user.svg")));
return;
}

QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
Q_UNUSED(size)
Q_UNUSED(requestedSize)
if (id.startsWith("user-id=")) {
// Format is "image://avatars/user-id=avatar-requested-user/local-user-id:0"
const auto userIdsString = id.split('=');
const auto userIds = userIdsString.last().split("/local-account:");
const auto avatarUserId = userIds.first();
const auto accountString = userIds.last();
const auto accountState = AccountManager::instance()->account(accountString);
Q_ASSERT(accountState);
Q_ASSERT(accountState->account());
if (!accountState || !accountState->account()) {
qCWarning(lcActivity) << "Invalid account:" << accountString;
return;
}
const auto avatarSize = requestedSize.width() > 0 ? requestedSize.width() : 64;
const auto avatarJob = new AvatarJob(accountState->account(), avatarUserId, avatarSize);
connect(avatarJob, &AvatarJob::avatarPixmap, this, [&](const QImage &avatarImg) {
handleDone(AvatarJob::makeCircularAvatar(avatarImg));
});
avatarJob->start();
return;
}

const auto makeIcon = [](const QString &path) {
QImage image(128, 128, QImage::Format_ARGB32);
image.fill(Qt::GlobalColor::transparent);
QPainter painter(&image);
QSvgRenderer renderer(path);
renderer.render(&painter);
return image;
};
handleDone(UserModel::instance()->avatarById(id.toInt()));
}

if (id == QLatin1String("fallbackWhite")) {
return makeIcon(QStringLiteral(":/client/theme/white/user.svg"));
void handleDone(const QImage &image)
{
_image = image;
emit finished();
}

if (id == QLatin1String("fallbackBlack")) {
return makeIcon(QStringLiteral(":/client/theme/black/user.svg"));
QQuickTextureFactory *textureFactory() const override
{
return QQuickTextureFactory::textureFactoryForImage(_image);
}

const int uid = id.toInt();
return UserModel::instance()->avatarById(uid);
private:
QImage _image;
};

QQuickImageResponse *ImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
{
const auto response = new class ImageResponse(id, requestedSize, &_pool);
return response;
}

/*-------------------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1720,3 +1759,4 @@ QHash<int, QByteArray> UserAppsModel::roleNames() const
return roles;
}
}

11 changes: 8 additions & 3 deletions src/gui/tray/usermodel.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef USERMODEL_H
#define USERMODEL_H

#include <QAbstractListModel>

Check failure on line 4 in src/gui/tray/usermodel.h

View workflow job for this annotation

GitHub Actions / build

src/gui/tray/usermodel.h:4:10 [clang-diagnostic-error]

'QAbstractListModel' file not found
#include <QImage>
#include <QDateTime>
#include <QStringList>
Expand Down Expand Up @@ -276,11 +276,16 @@
void buildUserList();
};

class ImageProvider : public QQuickImageProvider
class ImageProvider : public QQuickAsyncImageProvider
{
Q_OBJECT

public:
ImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
ImageProvider() = default;
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;

private:
QThreadPool _pool;
};

class UserAppsModel : public QAbstractListModel
Expand Down
Loading