Replaced AsyncReqComponent with some handles.

UI is no longer completely blocked during asynchronous operations.
This commit is contained in:
Aloshi 2014-03-18 19:55:37 -05:00
parent dbde900629
commit 1e8b040f73
12 changed files with 238 additions and 160 deletions

View file

@ -135,6 +135,7 @@ endif()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
#define basic sources and headers #define basic sources and headers
set(ES_HEADERS set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/AsyncHandle.h
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h ${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h ${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h ${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h

43
src/AsyncHandle.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
enum AsyncHandleStatus
{
ASYNC_IN_PROGRESS,
ASYNC_ERROR,
ASYNC_DONE
};
// Handle for some asynchronous operation.
class AsyncHandle
{
public:
AsyncHandle() : mStatus(ASYNC_IN_PROGRESS) {};
virtual void update() = 0;
// Update and return the latest status.
inline AsyncHandleStatus status() { update(); return mStatus; }
// User-friendly string of our current status. Will return error message if status() == SEARCH_ERROR.
inline std::string getStatusString()
{
switch(mStatus)
{
case ASYNC_IN_PROGRESS:
return "in progress";
case ASYNC_ERROR:
return mError;
case ASYNC_DONE:
return "done";
default:
return "something impossible has occured; row, row, fight the power";
}
}
protected:
inline void setStatus(AsyncHandleStatus status) { mStatus = status; }
inline void setError(const std::string& error) { setStatus(ASYNC_ERROR); mError = error; }
std::string mError;
AsyncHandleStatus mStatus;
};

View file

@ -144,14 +144,9 @@ HttpReq::Status HttpReq::status()
return mStatus; return mStatus;
} }
std::string HttpReq::getContent() std::string HttpReq::getContent() const
{ {
if(mStatus != REQ_SUCCESS) assert(mStatus == REQ_SUCCESS);
{
LOG(LogError) << "Called getContent() on an incomplete HttpReq!";
return "";
}
return mContent.str(); return mContent.str();
} }

View file

@ -42,7 +42,7 @@ public:
std::string getErrorMsg(); std::string getErrorMsg();
std::string getContent(); std::string getContent() const; // mStatus must be REQ_SUCCESS
static std::string urlEncode(const std::string &s); static std::string urlEncode(const std::string &s);
static bool isUrl(const std::string& s); static bool isUrl(const std::string& s);

View file

@ -116,6 +116,8 @@ void ComponentList::onCursorChanged(const CursorState& state)
mCameraOffset = 0; mCameraOffset = 0;
else if(mCameraOffset + mSize.y() > totalHeight) else if(mCameraOffset + mSize.y() > totalHeight)
mCameraOffset = totalHeight - mSize.y(); mCameraOffset = totalHeight - mSize.y();
}else{
mCameraOffset = 0;
} }
updateHelpPrompts(); updateHelpPrompts();

View file

@ -259,7 +259,7 @@ private:
ss << getSelectedObjects().size() << " SELECTED"; ss << getSelectedObjects().size() << " SELECTED";
mText.setText(ss.str()); mText.setText(ss.str());
mText.setSize(0, mText.getSize().y()); mText.setSize(0, mText.getSize().y());
setSize(mText.getSize().x() + mRightArrow.getSize().x() + 16, mText.getSize().y()); setSize(mText.getSize().x() + mRightArrow.getSize().x() + 24, mText.getSize().y());
if(mParent) // hack since theres no "on child size changed" callback atm... if(mParent) // hack since theres no "on child size changed" callback atm...
mParent->onSizeChanged(); mParent->onSizeChanged();
}else{ }else{
@ -270,7 +270,7 @@ private:
{ {
mText.setText(strToUpper(it->name)); mText.setText(strToUpper(it->name));
mText.setSize(0, mText.getSize().y()); mText.setSize(0, mText.getSize().y());
setSize(mText.getSize().x() + mLeftArrow.getSize().x() + mRightArrow.getSize().x() + 16, mText.getSize().y()); setSize(mText.getSize().x() + mLeftArrow.getSize().x() + mRightArrow.getSize().x() + 24, mText.getSize().y());
if(mParent) // hack since theres no "on child size changed" callback atm... if(mParent) // hack since theres no "on child size changed" callback atm...
mParent->onSizeChanged(); mParent->onSizeChanged();
break; break;

View file

@ -15,6 +15,8 @@ ScraperSearchComponent::ScraperSearchComponent(Window* window, SearchType type)
{ {
addChild(&mGrid); addChild(&mGrid);
mBlockAccept = false;
using namespace Eigen; using namespace Eigen;
// left spacer (empty component, needed for borders) // left spacer (empty component, needed for borders)
@ -87,6 +89,8 @@ void ScraperSearchComponent::search(const ScraperSearchParams& params)
{ {
mResultList->clear(); mResultList->clear();
mScraperResults.clear(); mScraperResults.clear();
mThumbnailReq.reset();
mMDResolveHandle.reset();
updateInfoPane(); updateInfoPane();
mLastSearch = params; mLastSearch = params;
@ -120,6 +124,7 @@ void ScraperSearchComponent::onSearchDone(const std::vector<ScraperSearchResult>
mGrid.resetCursor(); mGrid.resetCursor();
} }
mBlockAccept = false;
updateInfoPane(); updateInfoPane();
if(mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) if(mSearchType == ALWAYS_ACCEPT_FIRST_RESULT)
@ -177,6 +182,9 @@ bool ScraperSearchComponent::input(InputConfig* config, Input input)
{ {
if(config->isMappedTo("a", input) && input.value != 0) if(config->isMappedTo("a", input) && input.value != 0)
{ {
if(mBlockAccept)
return true;
//if you're on a result //if you're on a result
if(getSelectedIndex() != -1) if(getSelectedIndex() != -1)
{ {
@ -195,24 +203,28 @@ bool ScraperSearchComponent::input(InputConfig* config, Input input)
return ret; return ret;
} }
void ScraperSearchComponent::render(const Eigen::Affine3f& parentTrans)
{
Eigen::Affine3f trans = parentTrans * getTransform();
if(mBlockAccept)
{
Renderer::setMatrix(trans);
Renderer::drawRect((int)mResultList->getPosition().x(), (int)mResultList->getPosition().y(),
(int)mResultList->getSize().x(), (int)mResultList->getSize().y(), 0x00000011);
}
renderChildren(trans);
}
void ScraperSearchComponent::returnResult(ScraperSearchResult result) void ScraperSearchComponent::returnResult(ScraperSearchResult result)
{ {
mBlockAccept = true;
// resolve metadata image before returning // resolve metadata image before returning
if(!result.imageUrl.empty()) if(!result.imageUrl.empty())
{ {
downloadImageAsync(mWindow, result.imageUrl, getSaveAsPath(mLastSearch, "image", result.imageUrl), mMDResolveHandle = resolveMetaDataAssets(result, mLastSearch);
[this, result] (std::string filePath) mutable -> void
{
if(filePath.empty())
{
onSearchError("Error downloading boxart.");
return;
}
result.mdl.set("image", filePath);
result.imageUrl = "";
this->returnResult(result); // re-enter this function
});
return; return;
} }
@ -226,19 +238,30 @@ void ScraperSearchComponent::update(int deltaTime)
updateThumbnail(); updateThumbnail();
} }
if(mSearchHandle && mSearchHandle->status() != SEARCH_IN_PROGRESS) if(mSearchHandle && mSearchHandle->status() != ASYNC_IN_PROGRESS)
{ {
if(mSearchHandle->status() == SEARCH_DONE) if(mSearchHandle->status() == ASYNC_DONE)
{ {
onSearchDone(mSearchHandle->getResults()); onSearchDone(mSearchHandle->getResults());
}else if(mSearchHandle->status() == SEARCH_ERROR) }else if(mSearchHandle->status() == ASYNC_ERROR)
{ {
onSearchError(mSearchHandle->getStatusString()); onSearchError(mSearchHandle->getStatusString());
} }
mSearchHandle.reset(); mSearchHandle.reset();
} }
if(mMDResolveHandle && mMDResolveHandle->status() != ASYNC_IN_PROGRESS)
{
if(mMDResolveHandle->status() == ASYNC_DONE)
{
returnResult(mMDResolveHandle->getResult());
}else if(mMDResolveHandle->status() == ASYNC_ERROR)
{
onSearchError(mMDResolveHandle->getStatusString());
}
mMDResolveHandle.reset();
}
GuiComponent::update(deltaTime); GuiComponent::update(deltaTime);
} }

View file

@ -34,6 +34,7 @@ public:
bool input(InputConfig* config, Input input) override; bool input(InputConfig* config, Input input) override;
void update(int deltaTime) override; void update(int deltaTime) override;
void render(const Eigen::Affine3f& parentTrans) override;
std::vector<HelpPrompt> getHelpPrompts() override; std::vector<HelpPrompt> getHelpPrompts() override;
void onSizeChanged() override; void onSizeChanged() override;
void onFocusGained() override; void onFocusGained() override;
@ -65,8 +66,10 @@ private:
std::function<void(const ScraperSearchResult&)> mAcceptCallback; std::function<void(const ScraperSearchResult&)> mAcceptCallback;
std::function<void()> mSkipCallback; std::function<void()> mSkipCallback;
std::function<void()> mCancelCallback; std::function<void()> mCancelCallback;
bool mBlockAccept;
std::unique_ptr<ScraperSearchHandle> mSearchHandle; std::unique_ptr<ScraperSearchHandle> mSearchHandle;
std::unique_ptr<MDResolveHandle> mMDResolveHandle;
std::vector<ScraperSearchResult> mScraperResults; std::vector<ScraperSearchResult> mScraperResults;
std::unique_ptr<HttpReq> mThumbnailReq; std::unique_ptr<HttpReq> mThumbnailReq;
}; };

View file

@ -79,11 +79,14 @@ std::unique_ptr<ScraperSearchHandle> GamesDBScraper::getResultsAsync(const Scrap
GamesDBHandle::GamesDBHandle(const ScraperSearchParams& params, const std::string& url) : GamesDBHandle::GamesDBHandle(const ScraperSearchParams& params, const std::string& url) :
mReq(std::unique_ptr<HttpReq>(new HttpReq(url))) mReq(std::unique_ptr<HttpReq>(new HttpReq(url)))
{ {
setStatus(SEARCH_IN_PROGRESS); setStatus(ASYNC_IN_PROGRESS);
} }
void GamesDBHandle::update() void GamesDBHandle::update()
{ {
if(mStatus == ASYNC_DONE)
return;
if(mReq->status() == HttpReq::REQ_IN_PROGRESS) if(mReq->status() == HttpReq::REQ_IN_PROGRESS)
return; return;
@ -156,7 +159,7 @@ void GamesDBHandle::update()
game = game.next_sibling("Game"); game = game.next_sibling("Game");
} }
setStatus(SEARCH_DONE); setStatus(ASYNC_DONE);
setResults(results); setResults(results);
return; return;
} }

View file

@ -9,48 +9,116 @@
#include "GamesDBScraper.h" #include "GamesDBScraper.h"
#include "TheArchiveScraper.h" #include "TheArchiveScraper.h"
std::string ScraperSearchHandle::getStatusString() std::shared_ptr<Scraper> createScraperByName(const std::string& name)
{ {
switch(mStatus) if(name == "TheGamesDB")
return std::shared_ptr<Scraper>(new GamesDBScraper());
else if(name == "TheArchive")
return std::shared_ptr<Scraper>(new TheArchiveScraper());
return nullptr;
}
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result, const ScraperSearchParams& search)
{
return std::unique_ptr<MDResolveHandle>(new MDResolveHandle(result, search));
}
MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result, const ScraperSearchParams& search) : mResult(result)
{
if(!result.imageUrl.empty())
{ {
case SEARCH_IN_PROGRESS: std::string imgPath = getSaveAsPath(search, "image", result.imageUrl);
return "search in progress"; mFuncs.push_back(ResolvePair(downloadImageAsync(result.imageUrl, imgPath), [this, imgPath]
case SEARCH_ERROR: {
return mError; mResult.mdl.set("image", imgPath);
case SEARCH_DONE: mResult.imageUrl = "";
return "search done"; }));
default:
return "something impossible has occured";
} }
} }
std::string processFileDownload(std::shared_ptr<HttpReq> r, std::string saveAs) void MDResolveHandle::update()
{ {
if(r->status() != HttpReq::REQ_SUCCESS) if(mStatus == ASYNC_DONE || mStatus == ASYNC_ERROR)
return;
auto it = mFuncs.begin();
while(it != mFuncs.end())
{ {
LOG(LogError) << "Failed to download file - HttpReq error: " << r->getErrorMsg(); if(it->first->status() == ASYNC_ERROR)
return ""; {
setError(it->first->getStatusString());
return;
}else if(it->first->status() == ASYNC_DONE)
{
it->second();
it = mFuncs.erase(it);
continue;
}
it++;
} }
std::ofstream stream(saveAs, std::ios_base::out | std::ios_base::binary); if(mFuncs.empty())
if(stream.fail()) setStatus(ASYNC_DONE);
}
std::unique_ptr<AsyncHandle> downloadImageAsync(const std::string& url, const std::string& saveAs)
{
return std::unique_ptr<ImageDownloadHandle>(new ImageDownloadHandle(url, saveAs,
Settings::getInstance()->getInt("ScraperResizeWidth"), Settings::getInstance()->getInt("ScraperResizeHeight")));
}
ImageDownloadHandle::ImageDownloadHandle(const std::string& url, const std::string& path, int maxWidth, int maxHeight) :
mSavePath(path), mMaxWidth(maxWidth), mMaxHeight(maxHeight), mReq(new HttpReq(url))
{
}
void ImageDownloadHandle::update()
{
if(mReq->status() == HttpReq::REQ_IN_PROGRESS)
return;
if(mReq->status() != HttpReq::REQ_SUCCESS)
{ {
LOG(LogError) << "Failed to open \"" << saveAs << "\" for writing downloaded file."; std::stringstream ss;
return ""; ss << "Network error: " << mReq->getErrorMsg();
setError(ss.str());
return;
} }
std::string content = r->getContent(); // download is done, save it to disk
std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary);
if(stream.bad())
{
setError("Failed to open image path to write. Permission error? Disk full?");
return;
}
const std::string& content = mReq->getContent();
stream.write(content.data(), content.length()); stream.write(content.data(), content.length());
stream.close(); stream.close();
if(stream.bad())
{
setError("Failed to save image. Disk full?");
return;
}
return saveAs; // resize it
if(!resizeImage(mSavePath, mMaxWidth, mMaxHeight))
{
setError("Error saving resized image. Out of memory? Disk full?");
return;
}
setStatus(ASYNC_DONE);
} }
//you can pass 0 for width or height to keep aspect ratio //you can pass 0 for width or height to keep aspect ratio
void resizeImage(const std::string& path, int maxWidth, int maxHeight) bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
{ {
// nothing to do
if(maxWidth == 0 && maxHeight == 0) if(maxWidth == 0 && maxHeight == 0)
return; return true;
FREE_IMAGE_FORMAT format = FIF_UNKNOWN; FREE_IMAGE_FORMAT format = FIF_UNKNOWN;
FIBITMAP* image = NULL; FIBITMAP* image = NULL;
@ -62,7 +130,7 @@ void resizeImage(const std::string& path, int maxWidth, int maxHeight)
if(format == FIF_UNKNOWN) if(format == FIF_UNKNOWN)
{ {
LOG(LogError) << "Error - could not detect filetype for image \"" << path << "\"!"; LOG(LogError) << "Error - could not detect filetype for image \"" << path << "\"!";
return; return false;
} }
//make sure we can read this filetype first, then load it //make sure we can read this filetype first, then load it
@ -71,7 +139,7 @@ void resizeImage(const std::string& path, int maxWidth, int maxHeight)
image = FreeImage_Load(format, path.c_str()); image = FreeImage_Load(format, path.c_str());
}else{ }else{
LOG(LogError) << "Error - file format reading not supported for image \"" << path << "\"!"; LOG(LogError) << "Error - file format reading not supported for image \"" << path << "\"!";
return; return false;
} }
float width = (float)FreeImage_GetWidth(image); float width = (float)FreeImage_GetWidth(image);
@ -91,43 +159,16 @@ void resizeImage(const std::string& path, int maxWidth, int maxHeight)
if(imageRescaled == NULL) if(imageRescaled == NULL)
{ {
LOG(LogError) << "Could not resize image! (not enough memory? invalid bitdepth?)"; LOG(LogError) << "Could not resize image! (not enough memory? invalid bitdepth?)";
return; return false;
}
if(!FreeImage_Save(format, imageRescaled, path.c_str()))
{
LOG(LogError) << "Failed to save resized image!";
} }
bool saved = FreeImage_Save(format, imageRescaled, path.c_str());
FreeImage_Unload(imageRescaled); FreeImage_Unload(imageRescaled);
}
void downloadImageAsync(Window* window, const std::string& url, const std::string& saveAs, std::function<void(std::string)> returnFunc) if(!saved)
{ LOG(LogError) << "Failed to save resized image!";
std::shared_ptr<HttpReq> httpreq = std::make_shared<HttpReq>(url);
AsyncReqComponent* req = new AsyncReqComponent(window, httpreq,
[returnFunc, saveAs] (std::shared_ptr<HttpReq> r)
{
std::string file = processFileDownload(r, saveAs);
if(!file.empty())
resizeImage(file, Settings::getInstance()->getInt("ScraperResizeWidth"), Settings::getInstance()->getInt("ScraperResizeHeight"));
returnFunc(file);
}, NULL);
window->pushGui(req); return saved;
}
std::string downloadImage(const std::string& url, const std::string& saveAs)
{
std::shared_ptr<HttpReq> httpreq = std::make_shared<HttpReq>(url);
while(httpreq->status() == HttpReq::REQ_IN_PROGRESS);
std::string file = processFileDownload(httpreq, saveAs);
if(!file.empty())
resizeImage(file, Settings::getInstance()->getInt("ScraperResizeWidth"), Settings::getInstance()->getInt("ScraperResizeHeight"));
return file;
} }
std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url) std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url)
@ -153,42 +194,3 @@ std::string getSaveAsPath(const ScraperSearchParams& params, const std::string&
path += name + ext; path += name + ext;
return path; return path;
} }
std::shared_ptr<Scraper> createScraperByName(const std::string& name)
{
if(name == "TheGamesDB")
return std::shared_ptr<Scraper>(new GamesDBScraper());
else if(name == "TheArchive")
return std::shared_ptr<Scraper>(new TheArchiveScraper());
return nullptr;
}
void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& params, MetaDataList mdl, std::function<void(MetaDataList)> returnFunc)
{
const std::vector<MetaDataDecl>& mdd = params.game->metadata.getMDD();
for(auto it = mdd.begin(); it != mdd.end(); it++)
{
std::string key = it->key;
std::string val = mdl.get(key);
if(it->type == MD_IMAGE_PATH && HttpReq::isUrl(val))
{
downloadImageAsync(window, val, getSaveAsPath(params, key, val), [window, params, mdl, key, returnFunc] (std::string savedAs) mutable ->
void
{
if(savedAs.empty())
{
//error
LOG(LogError) << "Could not resolve image for [" << getCleanFileName(params.game->getPath()) << "]! Skipping.";
}
mdl.set(key, savedAs);
resolveMetaDataAssetsAsync(window, params, mdl, returnFunc);
});
return;
}
}
returnFunc(mdl);
}

View file

@ -3,11 +3,10 @@
#include "../MetaData.h" #include "../MetaData.h"
#include "../SystemData.h" #include "../SystemData.h"
#include "../HttpReq.h" #include "../HttpReq.h"
#include "../AsyncHandle.h"
#include <vector> #include <vector>
#include <functional> #include <functional>
class Window;
struct ScraperSearchParams struct ScraperSearchParams
{ {
SystemData* system; SystemData* system;
@ -25,34 +24,16 @@ struct ScraperSearchResult
std::string thumbnailUrl; std::string thumbnailUrl;
}; };
enum ScraperSearchStatus class ScraperSearchHandle : public AsyncHandle
{
SEARCH_IN_PROGRESS,
SEARCH_ERROR,
SEARCH_DONE
};
class ScraperSearchHandle
{ {
public: public:
virtual void update() = 0; virtual void update() = 0;
inline const std::vector<ScraperSearchResult>& getResults() const { assert(mStatus != ASYNC_IN_PROGRESS); return mResults; }
// Update and return the latest status.
inline ScraperSearchStatus status() { update(); return mStatus; }
// User-friendly string of our current status. Will return error message if status() == SEARCH_ERROR.
std::string getStatusString();
inline const std::vector<ScraperSearchResult>& getResults() const { assert(mStatus != SEARCH_IN_PROGRESS); return mResults; }
protected: protected:
inline void setError(const std::string& error) { setStatus(SEARCH_ERROR); mError = error; }
inline void setStatus(ScraperSearchStatus status) { mStatus = status; }
inline void setResults(const std::vector<ScraperSearchResult>& results) { mResults = results; } inline void setResults(const std::vector<ScraperSearchResult>& results) { mResults = results; }
private: private:
std::string mError;
ScraperSearchStatus mStatus;
std::vector<ScraperSearchResult> mResults; std::vector<ScraperSearchResult> mResults;
}; };
@ -67,23 +48,48 @@ public:
std::shared_ptr<Scraper> createScraperByName(const std::string& name); std::shared_ptr<Scraper> createScraperByName(const std::string& name);
// Meta data asset downloading stuff.
class MDResolveHandle : public AsyncHandle
{
public:
MDResolveHandle(const ScraperSearchResult& result, const ScraperSearchParams& search);
void update() override;
inline const ScraperSearchResult& getResult() const { assert(mStatus == ASYNC_DONE); return mResult; }
private:
ScraperSearchResult mResult;
typedef std::pair< std::unique_ptr<AsyncHandle>, std::function<void()> > ResolvePair;
std::vector<ResolvePair> mFuncs;
};
class ImageDownloadHandle : public AsyncHandle
{
public:
ImageDownloadHandle(const std::string& url, const std::string& path, int maxWidth, int maxHeight);
void update() override;
private:
std::unique_ptr<HttpReq> mReq;
std::string mSavePath;
int mMaxWidth;
int mMaxHeight;
};
//About the same as "~/.emulationstation/downloaded_images/[system_name]/[game_name].[url's extension]". //About the same as "~/.emulationstation/downloaded_images/[system_name]/[game_name].[url's extension]".
//Will create the "downloaded_images" and "subdirectory" directories if they do not exist. //Will create the "downloaded_images" and "subdirectory" directories if they do not exist.
std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url); std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url);
//Returns the path to the downloaded file (saveAs) on completion.
//Returns empty string if an error occured.
//Will resize according to Settings::getInt("ScraperResizeWidth") and Settings::getInt("ScraperResizeHeight"). //Will resize according to Settings::getInt("ScraperResizeWidth") and Settings::getInt("ScraperResizeHeight").
std::string downloadImage(const std::string& url, const std::string& saveAs); std::unique_ptr<AsyncHandle> downloadImageAsync(const std::string& url, const std::string& saveAs);
//Returns (via returnFunc) the path to the downloaded file (saveAs) on completion. // Resolves all metadata assets that need to be downloaded.
//Returns empty string if an error occured. std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result, const ScraperSearchParams& search);
//Will resize according to Settings::getInt("ScraperResizeWidth") and Settings::getInt("ScraperResizeHeight").
//Same as downloadImage, just async.
void downloadImageAsync(Window* window, const std::string& url, const std::string& saveAs, std::function<void(std::string)> returnFunc);
void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& params, MetaDataList mdl, std::function<void(MetaDataList)> returnFunc);
//You can pass 0 for maxWidth or maxHeight to automatically keep the aspect ratio. //You can pass 0 for maxWidth or maxHeight to automatically keep the aspect ratio.
//Will overwrite the image at [path] with the new resized one. //Will overwrite the image at [path] with the new resized one.
void resizeImage(const std::string& path, int maxWidth, int maxHeight); //Returns true if successful, false otherwise.
bool resizeImage(const std::string& path, int maxWidth, int maxHeight);

View file

@ -25,12 +25,12 @@ std::unique_ptr<ScraperSearchHandle> TheArchiveScraper::getResultsAsync(const Sc
TheArchiveHandle::TheArchiveHandle(const ScraperSearchParams& params, const std::string& url) : TheArchiveHandle::TheArchiveHandle(const ScraperSearchParams& params, const std::string& url) :
mReq(std::unique_ptr<HttpReq>(new HttpReq(url))) mReq(std::unique_ptr<HttpReq>(new HttpReq(url)))
{ {
setStatus(SEARCH_IN_PROGRESS); setStatus(ASYNC_IN_PROGRESS);
} }
void TheArchiveHandle::update() void TheArchiveHandle::update()
{ {
if(status() == SEARCH_DONE) if(mStatus == ASYNC_DONE)
return; return;
if(mReq->status() == HttpReq::REQ_IN_PROGRESS) if(mReq->status() == HttpReq::REQ_IN_PROGRESS)
@ -91,6 +91,6 @@ void TheArchiveHandle::update()
game = game.next_sibling("game"); game = game.next_sibling("game");
} }
setStatus(SEARCH_DONE); setStatus(ASYNC_DONE);
setResults(results); setResults(results);
} }