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