mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-25 06:25:56 +03:00
Merge pull request #7373 from nextcloud/feature/display-sharedwithme-info
Show received share information in share view
This commit is contained in:
commit
16a2f0d5c4
6 changed files with 195 additions and 31 deletions
|
@ -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
|
||||
|
|
|
@ -220,11 +220,21 @@ void ShareModel::resetData()
|
|||
_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();
|
||||
Q_EMIT shareOwnerDisplayNameChanged();
|
||||
Q_EMIT shareOwnerAvatarChanged();
|
||||
Q_EMIT sharedWithMeExpiresChanged();
|
||||
Q_EMIT sharedWithMeRemainingTimeStringChanged();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
@ -319,7 +329,9 @@ void ShareModel::updateData()
|
|||
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) {
|
||||
|
@ -477,14 +489,38 @@ void ShareModel::slotSharesFetched(const QList<SharePtr> &shares)
|
|||
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();
|
||||
|
||||
slotAddShare(share);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform forward pass on shares and check for duplicate display names; store these indeces so
|
||||
|
@ -1379,6 +1415,31 @@ bool ShareModel::isShareDisabledEncryptedFolder() const
|
|||
return _isShareDisabledEncryptedFolder;
|
||||
}
|
||||
|
||||
bool ShareModel::displayShareOwner() const
|
||||
{
|
||||
return _displayShareOwner;
|
||||
}
|
||||
|
||||
QString ShareModel::shareOwnerDisplayName() const
|
||||
{
|
||||
return _shareOwnerDisplayName;
|
||||
}
|
||||
|
||||
QString ShareModel::shareOwnerAvatar() const
|
||||
{
|
||||
return _shareOwnerAvatar;
|
||||
}
|
||||
|
||||
QString ShareModel::sharedWithMeRemainingTimeString() const
|
||||
{
|
||||
return _sharedWithMeRemainingTimeString;
|
||||
}
|
||||
|
||||
bool ShareModel::sharedWithMeExpires() const
|
||||
{
|
||||
return _sharedWithMeExpires;
|
||||
}
|
||||
|
||||
QVariantList ShareModel::sharees() const
|
||||
{
|
||||
QVariantList returnSharees;
|
||||
|
|
|
@ -38,6 +38,11 @@ class ShareModel : public QAbstractListModel
|
|||
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 {
|
||||
|
@ -126,6 +131,12 @@ public:
|
|||
|
||||
[[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:
|
||||
|
@ -143,6 +154,11 @@ signals:
|
|||
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);
|
||||
|
@ -246,6 +262,11 @@ private:
|
|||
SyncJournalFileLockInfo _filelockState;
|
||||
QString _privateLinkUrl;
|
||||
QByteArray _fileRemoteId;
|
||||
bool _displayShareOwner = false;
|
||||
QString _shareOwnerDisplayName;
|
||||
QString _shareOwnerAvatar;
|
||||
bool _sharedWithMeExpires = false;
|
||||
QString _sharedWithMeRemainingTimeString;
|
||||
|
||||
QSharedPointer<ShareManager> _manager;
|
||||
|
||||
|
|
|
@ -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(QString::fromLatin1("shared_with_me"), QString("true"));
|
||||
|
||||
for (auto it = std::cbegin(params); it != std::cend(params); ++it) {
|
||||
addParam(it.key(), it.value());
|
||||
|
|
|
@ -1618,35 +1618,82 @@ 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)
|
||||
|
||||
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
Q_UNUSED(requestedSize)
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (id == QLatin1String("fallbackWhite")) {
|
||||
return makeIcon(QStringLiteral(":/client/theme/white/user.svg"));
|
||||
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 account = accountState->account();
|
||||
const auto qnam = account->networkAccessManager();
|
||||
|
||||
QMetaObject::invokeMethod(qnam, [this, requestedSize, avatarUserId, account]() {
|
||||
const auto avatarSize = requestedSize.width() > 0 ? requestedSize.width() : 64;
|
||||
const auto avatarJob = new AvatarJob(account, avatarUserId, avatarSize);
|
||||
connect(avatarJob, &AvatarJob::avatarPixmap, this, [&](const QImage &avatarImg) {
|
||||
QMetaObject::invokeMethod(this, [this, avatarImg] {
|
||||
handleDone(AvatarJob::makeCircularAvatar(avatarImg));
|
||||
});
|
||||
});
|
||||
avatarJob->start();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
handleDone(UserModel::instance()->avatarById(id.toInt()));
|
||||
}
|
||||
|
||||
if (id == QLatin1String("fallbackBlack")) {
|
||||
return makeIcon(QStringLiteral(":/client/theme/black/user.svg"));
|
||||
void handleDone(const QImage &image)
|
||||
{
|
||||
_image = image;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
const int uid = id.toInt();
|
||||
return UserModel::instance()->avatarById(uid);
|
||||
QQuickTextureFactory *textureFactory() const override
|
||||
{
|
||||
return QQuickTextureFactory::textureFactoryForImage(_image);
|
||||
}
|
||||
|
||||
private:
|
||||
QImage _image;
|
||||
};
|
||||
|
||||
QQuickImageResponse *ImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
||||
{
|
||||
const auto response = new class ImageResponse(id, requestedSize, &_pool);
|
||||
return response;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
|
@ -1725,3 +1772,4 @@ QHash<int, QByteArray> UserAppsModel::roleNames() const
|
|||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -276,11 +276,16 @@ private:
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue