From 80afe976a872435e029b57ff70952f1917c4ff74 Mon Sep 17 00:00:00 2001 From: cinder <cinder@cinderblocks.biz> Date: Mon, 12 Dec 2022 20:11:20 -0600 Subject: [PATCH] Move LLProfileImagePicker to its own file for use by Legacy Profiles --- indra/newview/CMakeLists.txt | 2 + indra/newview/llpanelprofile.cpp | 237 +------------------------ indra/newview/llpanelprofile.h | 1 + indra/newview/llprofileimagepicker.cpp | 219 +++++++++++++++++++++++ indra/newview/llprofileimagepicker.h | 53 ++++++ 5 files changed, 280 insertions(+), 232 deletions(-) create mode 100644 indra/newview/llprofileimagepicker.cpp create mode 100644 indra/newview/llprofileimagepicker.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5c954f41f92..785e2b4eee9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -611,6 +611,7 @@ set(viewer_SOURCE_FILES llpreviewtexture.cpp llproductinforequest.cpp llprogressview.cpp + llprofileimagepicker.cpp llrecentpeople.cpp llregioninfomodel.cpp llregionposition.cpp @@ -1304,6 +1305,7 @@ set(viewer_HEADER_FILES llpreviewsound.h llpreviewtexture.h llproductinforequest.h + llprofileimagepicker.h llprogressview.h llrecentpeople.h llregioninfomodel.h diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 8404ea0f072..606864519cb 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -306,153 +306,6 @@ void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data) LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Data: " << data << " Result: " << httpResults << LL_ENDL; } -LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::string path_to_image, LLHandle<LLPanel> *handle) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders; - - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - httpOpts->setFollowRedirects(true); - - LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - // todo: notification? - LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL; - return LLUUID::null; - } - if (!result.has("uploader")) - { - // todo: notification? - LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL; - return LLUUID::null; - } - std::string uploader_cap = result["uploader"].asString(); - if (uploader_cap.empty()) - { - LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL; - return LLUUID::null; - } - - // Upload the image - - LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); - LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); - S64 length; - - { - llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate); - if (!instream.is_open()) - { - LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL; - return LLUUID::null; - } - length = instream.tellg(); - } - - uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional - uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required! - uploaderhttpOpts->setFollowRedirects(true); - - result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders); - - httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - LL_WARNS("AvatarProperties") << result << LL_ENDL; - - if (!status) - { - LL_WARNS("AvatarProperties") << "Failed to upload image " << status.toString() << LL_ENDL; - return LLUUID::null; - } - - if (result["state"].asString() != "complete") - { - if (result.has("message")) - { - LL_WARNS("AvatarProperties") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL; - } - else - { - LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL; - } - return LLUUID::null; - } - - return result["new_asset"].asUUID(); -} - -enum EProfileImageType -{ - PROFILE_IMAGE_SL, - PROFILE_IMAGE_FL, -}; - -void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image, LLHandle<LLPanel> *handle) -{ - LLSD data; - switch (type) - { - case PROFILE_IMAGE_SL: - data["profile-image-asset"] = "sl_image_id"; - break; - case PROFILE_IMAGE_FL: - data["profile-image-asset"] = "fl_image_id"; - break; - } - - LLUUID result = post_profile_image(cap_url, data, path_to_image, handle); - - // reset loading indicator - if (!handle->isDead()) - { - switch (type) - { - case PROFILE_IMAGE_SL: - { - LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(handle->get()); - if (result.notNull()) - { - panel->setProfileImageUploaded(result); - } - else - { - // failure, just stop progress indicator - panel->setProfileImageUploading(false); - } - break; - } - case PROFILE_IMAGE_FL: - { - LLPanelProfileFirstLife* panel = static_cast<LLPanelProfileFirstLife*>(handle->get()); - if (result.notNull()) - { - panel->setProfileImageUploaded(result); - } - else - { - // failure, just stop progress indicator - panel->setProfileImageUploading(false); - } - break; - } - } - } - - // Cleanup - LLFile::remove(path_to_image); - delete handle; -} - ////////////////////////////////////////////////////////////////////////// // LLProfileHandler @@ -1289,94 +1142,12 @@ void LLPanelProfileSecondLife::setLoaded() } } - - -class LLProfileImagePicker : public LLFilePickerThread -{ -public: - LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel> *handle); - ~LLProfileImagePicker(); - void notify(const std::vector<std::string>& filenames) override; - -private: - LLHandle<LLPanel> *mHandle; - EProfileImageType mType; -}; - -LLProfileImagePicker::LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel> *handle) - : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE), - mHandle(handle), - mType(type) -{ -} - -LLProfileImagePicker::~LLProfileImagePicker() -{ - delete mHandle; -} - -void LLProfileImagePicker::notify(const std::vector<std::string>& filenames) -{ - if (mHandle->isDead()) - { - return; - } - if (filenames.empty()) - { - return; - } - std::string file_path = filenames[0]; - if (file_path.empty()) - { - return; - } - - // generate a temp texture file for coroutine - std::string temp_file = gDirUtilp->getTempFilename(); - U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path)); - const S32 MAX_DIM = 256; - if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) - { - //todo: image not supported notification - LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL; - return; - } - - std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); - if (cap_url.empty()) - { - LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL; - return; - } - - switch (mType) - { - case PROFILE_IMAGE_SL: - { - LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(mHandle->get()); - panel->setProfileImageUploading(true); - } - break; - case PROFILE_IMAGE_FL: - { - LLPanelProfileFirstLife* panel = static_cast<LLPanelProfileFirstLife*>(mHandle->get()); - panel->setProfileImageUploading(true); - } - break; - } - - LLCoros::instance().launch("postAgentUserImageCoro", - boost::bind(post_profile_image_coro, cap_url, mType, temp_file, mHandle)); - - mHandle = nullptr; // transferred to post_profile_image_coro -} - void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) { const std::string item_name = userdata.asString(); const LLUUID agent_id = getAvatarId(); // todo: consider moving this into LLAvatarActions::onCommit(name, id) - // and making all other flaoters, like people menu do the same + // and making all other floaters, like people menu, do the same if (item_name == "im") { LLAvatarActions::startIM(agent_id); @@ -1469,7 +1240,8 @@ void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) } else if (item_name == "upload_photo") { - (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle<LLPanel>(getHandle())))->getFile(); + (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle<LLPanel>(getHandle()), + [this] (LLUUID const& id) { setProfileImageUploaded(id); }))->getFile(); LLFloater* floaterp = mFloaterTexturePickerHandle.get(); if (floaterp) @@ -2053,7 +1825,8 @@ void LLPanelProfileFirstLife::commitUnsavedChanges() void LLPanelProfileFirstLife::onUploadPhoto() { - (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle<LLPanel>(getHandle())))->getFile(); + (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle<LLPanel>(getHandle()), + [this](LLUUID const& id) { setProfileImageUploaded(id); }))->getFile(); LLFloater* floaterp = mFloaterTexturePickerHandle.get(); if (floaterp) diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 215594bc467..a3e7be9cc4c 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -33,6 +33,7 @@ #include "llpanel.h" #include "llpanelavatar.h" #include "llmediactrl.h" +#include "llprofileimagepicker.h" #include "llvoiceclient.h" // class LLPanelProfileClassifieds; diff --git a/indra/newview/llprofileimagepicker.cpp b/indra/newview/llprofileimagepicker.cpp new file mode 100644 index 00000000000..769b3680dba --- /dev/null +++ b/indra/newview/llprofileimagepicker.cpp @@ -0,0 +1,219 @@ +/** +* @file llprofileimagepicker.cpp +* @brief Specialized profile image filepicker +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llprofileimagepicker.h" + +#include "llagent.h" +#include "llloadingindicator.h" +#include "llpanel.h" +#include "llviewertexturelist.h" + +static constexpr std::string_view PROFILE_IMAGE_UPLOAD_CAP("UploadAgentProfileImage"); + +static void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image, + LLProfileImagePicker::ugly_picker_cb_t cb); +static LLUUID post_profile_image(std::string cap_url, const LLSD& first_data, std::string path_to_image); +static void setImageUploading(LLPanel* panel, bool loading); + + +LLProfileImagePicker::LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel>* handle, ugly_picker_cb_t const& cb) +: LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE) +, mHandle(handle) +, mType(type), + mCallback(cb) +{ } + +LLProfileImagePicker::~LLProfileImagePicker() +{ + delete mHandle; +} + +void LLProfileImagePicker::notify(const std::vector<std::string>& filenames) +{ + if (mHandle->isDead()) + { + return; + } + if (filenames.empty()) + { + return; + } + const std::string& file_path = filenames.at(0); + if (file_path.empty()) + { + return; + } + + // generate a temp texture file for coroutine + std::string const& temp_file = gDirUtilp->getTempFilename(); + U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path)); + const S32 MAX_DIM = 256; + if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) + { + //todo: image not supported notification + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL; + return; + } + + std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); + if (cap_url.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL; + return; + } + + setImageUploading(mHandle->get(), true); + LLCoros::instance().launch("postAgentUserImageCoro", + [cap_url, this, temp_file] + { + return post_profile_image_coro(cap_url, mType, temp_file, mCallback); + }); +} + +LLUUID post_profile_image(std::string cap_url, const LLSD& first_data, std::string path_to_image) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( + new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL; + return LLUUID::null; + } + if (!result.has("uploader")) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL; + return LLUUID::null; + } + std::string uploader_cap = result["uploader"].asString(); + if (uploader_cap.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL; + return LLUUID::null; + } + + // Upload the image + + LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); + S64 length; + + { + llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate); + if (!instream.is_open()) + { + LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL; + return LLUUID::null; + } + length = instream.tellg(); + } + + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required! + uploaderhttpOpts->setFollowRedirects(true); + + result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders); + + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LL_WARNS("AvatarProperties") << result << LL_ENDL; + + if (!status) + { + LL_WARNS("AvatarProperties") << "Failed to upload image " << status.toString() << LL_ENDL; + return LLUUID::null; + } + + if (result["state"].asString() != "complete") + { + if (result.has("message")) + { + LL_WARNS("AvatarProperties") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL; + } + else + { + LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL; + } + return LLUUID::null; + } + + return result["new_asset"].asUUID(); +} + +void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image, + LLProfileImagePicker::ugly_picker_cb_t cb) +{ + LLSD data; + switch (type) + { + case PROFILE_IMAGE_SL: + data["profile-image-asset"] = "sl_image_id"; + break; + case PROFILE_IMAGE_FL: + data["profile-image-asset"] = "fl_image_id"; + break; + } + + LLUUID result = post_profile_image(cap_url, data, path_to_image); + + cb(result); + + // Cleanup + LLFile::remove(path_to_image); +} + +void setImageUploading(LLPanel* panel, bool loading) +{ + LLLoadingIndicator* indicator = panel->findChild<LLLoadingIndicator>("image_upload_indicator"); + if (indicator) + { + indicator->setVisible(loading); + if (loading) + { + indicator->start(); + } + else + { + indicator->stop(); + } + } +} diff --git a/indra/newview/llprofileimagepicker.h b/indra/newview/llprofileimagepicker.h new file mode 100644 index 00000000000..a67d0859b08 --- /dev/null +++ b/indra/newview/llprofileimagepicker.h @@ -0,0 +1,53 @@ +/** +* @file llprofileimagepicker.h +* @brief Specialized profile image filepicker +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_PROFILEIMAGEPICKER_H +#define LL_PROFILEIMAGEPICKER_H + +#include "llviewermenufile.h" + +enum EProfileImageType +{ + PROFILE_IMAGE_SL, + PROFILE_IMAGE_FL, +}; + +class LLProfileImagePicker final : public LLFilePickerThread +{ +public: + typedef std::function<void(LLUUID const&)> ugly_picker_cb_t; + + LLProfileImagePicker(EProfileImageType type, LLHandle<LLPanel>* handle, ugly_picker_cb_t const& cb); + ~LLProfileImagePicker() override; + void notify(const std::vector<std::string>& filenames) override; + +private: + LLHandle<LLPanel>* mHandle; + EProfileImageType mType; + ugly_picker_cb_t mCallback; +}; + +#endif // LL_PROFILEIMAGEPICKER_H -- GitLab