#include "Avatar.h" #include "FullName.h" #include "megaapi.h" #include "mega/types.h" #include "AvatarWidget.h" #include "MegaApplication.h" #include "Preferences.h" namespace UserAttributes { // AVATAR REQUEST // // The Avatar is either (in order of preference) // - an image set by the user // - the first letter of the user's name // - the first letter of the user's email // // The flow is the following: // 1. Request the user's avatar // 2. When the Avatar request comes back: // 2.a. If we have a picture, use it and emit attributeReady(). // 2.b. If not, request the full name // 3. When the request for fullname comes back: // 3.a. Update the symbol info with the fisrt symbol from the user's first name // 3.b. If we don't have the Name either, use the first letter from the user's email // 3.c. Emit attributeReady() // // The avatar is updated on attribute change. If there is no picture, see above. // Avatar::Avatar(const QString &userEmail) : AttributeRequest(userEmail), mUseImgFile(true) { mLetterAvatarInfo.clear(); } std::shared_ptr Avatar::requestAvatar(const char *user_email) { return UserAttributesManager::instance().requestAttribute(user_email); } void Avatar::onRequestFinish(mega::MegaApi*, mega::MegaRequest* incoming_request, mega::MegaError* e) { if(incoming_request->getParamType() == mega::MegaApi::USER_ATTR_AVATAR) { mUseImgFile = false; auto errorCode (e->getErrorCode()); if (errorCode == mega::MegaError::API_OK) { mIconPath = QString::fromUtf8(incoming_request->getFile()); #ifdef WIN32 if (mIconPath.startsWith(QString::fromUtf8("\\\\?\\"))) { mIconPath = mIconPath.mid(4); } #endif if (QFile::exists(mIconPath)) { mUseImgFile = true; mIcon.clear(); } if (mFullName) { disconnect(mFullName.get(), &FullName::fullNameReady, this, &Avatar::onFullNameAttributeReady); } } else { if(!mIconPath.isEmpty()) { QFile::remove(mIconPath); mIconPath.clear(); } mIcon.clear(); if (!mFullName) { mFullName = FullName::requestFullName(getEmail().toUtf8().constData()); } connect(mFullName.get(), &FullName::fullNameReady, this, &Avatar::onFullNameAttributeReady, Qt::UniqueConnection); onFullNameAttributeReady(); } if (isAttributeReady()) { emit attributeReady(); } } } AttributeRequest::RequestInfo Avatar::fillRequestInfo() { std::function avatarRequestFunc = [this]() { mUseImgFile = false; mLetterAvatarInfo.symbol.clear(); QString email (getEmail()); QString avatarPath (Utilities::getAvatarPath(email.isEmpty() ? Preferences::instance()->email() : email)); MegaSyncApp->getMegaApi()->getUserAvatar(email.isEmpty() ? nullptr : email.toUtf8().constData(), avatarPath.toUtf8().constData()); }; QSharedPointer avatarParamInfo(new ParamInfo(avatarRequestFunc)); ParamInfoMap paramInfo({{mega::MegaApi::USER_ATTR_AVATAR, avatarParamInfo}}); RequestInfo ret(paramInfo, QMap({{mega::MegaUser::CHANGE_TYPE_AVATAR, mega::MegaApi::USER_ATTR_AVATAR}})); return ret; } void Avatar::requestAttribute() { requestUserAttribute(mega::MegaApi::USER_ATTR_AVATAR); } void Avatar::onFullNameAttributeReady() { // This case handles the situation when the name changes and the user does not // have an avatar set. Only emit if the symbol changes. auto oldSymbol (mLetterAvatarInfo.symbol); fillLetterInfo(); if (!mUseImgFile && oldSymbol != mLetterAvatarInfo.symbol) { mIcon.clear(); emit attributeReady(); } } void Avatar::fillLetterInfo() { if (mFullName && !mFullName->isRequestPending()) { getLetterColor(); auto name = mFullName->getFullName(); if(!name.isEmpty()) { auto c (name.cbegin()); mLetterAvatarInfo.symbol = c->toUpper(); if (c->isHighSurrogate() && ++c != name.cend() && c->isLowSurrogate()) { mLetterAvatarInfo.symbol += *c; } } } } void Avatar::getLetterColor() { if (mLetterAvatarInfo.colorNeedsRefresh) { auto api = MegaSyncApp->getMegaApi(); auto avatarEmail (getEmail()); mega::MegaHandle userHandle (mega::INVALID_HANDLE); if (avatarEmail.isEmpty() || avatarEmail == Preferences::instance()->email()) { userHandle = api->getMyUserHandleBinary(); } else { std::unique_ptr user (api->getContact(avatarEmail.toUtf8().constData())); if (user) { userHandle = user->getHandle(); } } std::unique_ptr userHandleStr (api->userHandleToBase64(userHandle)); std::unique_ptr primaryColor (api->getUserAvatarColor(userHandleStr.get())); mLetterAvatarInfo.primaryColor = QColor(primaryColor.get()); std::unique_ptr secondaryColor (api->getUserAvatarSecondaryColor(userHandleStr.get())); mLetterAvatarInfo.secondaryColor = QColor(secondaryColor.get()); mLetterAvatarInfo.colorNeedsRefresh = userHandle != mega::INVALID_HANDLE; } } const QPixmap& Avatar::getPixmap(const int& size) const { auto& icon = mIcon[size]; if(icon.isNull()) { if(!mUseImgFile) { // If the attribute is not ready, use the first char of the email as a placeholder. icon = AvatarPixmap::createFromLetter(isAttributeReady() ? mLetterAvatarInfo.symbol : getEmail().at(0).toUpper(), mLetterAvatarInfo.primaryColor, mLetterAvatarInfo.secondaryColor, size); } else { icon = AvatarPixmap::maskFromImagePath(mIconPath, size); } } return icon; } bool Avatar::isAttributeReady() const { // We need to have at least 1 valid avatar return !mLetterAvatarInfo.isEmpty() || !mIconPath.isEmpty(); } }//end namespace UserAttributes