diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index cfd61045a3..1fbab9ab6a 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -138,32 +138,49 @@ private: class SortedLinearLayout : public UI::LinearLayoutList { public: + typedef std::function PrepFunc; typedef std::function CompareFunc; - typedef std::function DoneFunc; SortedLinearLayout(UI::Orientation orientation, UI::LayoutParams *layoutParams = nullptr) : UI::LinearLayoutList(orientation, layoutParams) { } - void SetCompare(CompareFunc lessFunc, DoneFunc doneFunc) { + void SetCompare(const PrepFunc &prepFunc, const CompareFunc &lessFunc) { + prepIndex_ = 0; + prepFunc_ = prepFunc; lessFunc_ = lessFunc; - doneFunc_ = doneFunc; } void Update() override; private: + size_t prepIndex_ = 0; + PrepFunc prepFunc_; CompareFunc lessFunc_; - DoneFunc doneFunc_; }; void SortedLinearLayout::Update() { + if (prepFunc_) { + // Try to avoid dropping more than a frame, prefer items shift. + constexpr double ALLOWED_TIME = 0.95 / 60.0; + double start_time = time_now_d(); + for (; prepIndex_ < views_.size(); ++prepIndex_) { + prepFunc_(views_[prepIndex_]); + if (time_now_d() > start_time + ALLOWED_TIME) { + break; + } + } + } if (lessFunc_) { + // We may sort several times while calculating. std::stable_sort(views_.begin(), views_.end(), lessFunc_); } - if (doneFunc_ && doneFunc_()) { + // We're done if we got through all items. + if (prepIndex_ >= views_.size()) { + prepFunc_ = PrepFunc(); lessFunc_ = CompareFunc(); } + UI::LinearLayout::Update(); } @@ -184,14 +201,57 @@ public: const Path &GamePath() const { return savePath_; } + uint64_t GetTotalSize() const { + return totalSize_; + } + int64_t GetDateSeconds() const { + return dateSeconds_; + } + + void UpdateTotalSize(); + void UpdateDateSeconds(); + private: void UpdateText(const std::shared_ptr &ginfo); Path savePath_; std::string title_; std::string subtitle_; + uint64_t totalSize_ = 0; + int64_t dateSeconds_ = 0; + bool hasTotalSize_ = false; + bool hasDateSeconds_ = false; }; +void SavedataButton::UpdateTotalSize() { + if (hasTotalSize_) + return; + + File::FileInfo info; + if (File::GetFileInfo(savePath_, &info)) { + totalSize_ = info.size; + if (info.isDirectory) + totalSize_ = File::ComputeRecursiveDirectorySize(savePath_); + } + + hasTotalSize_ = true; +} + +void SavedataButton::UpdateDateSeconds() { + if (hasDateSeconds_) + return; + + File::FileInfo info; + if (File::GetFileInfo(savePath_, &info)) { + dateSeconds_ = info.mtime; + if (info.isDirectory && File::GetFileInfo(savePath_ / "PARAM.SFO", &info)) { + dateSeconds_ = info.mtime; + } + } + + hasDateSeconds_ = true; +} + UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) { std::shared_ptr ginfo = g_gameInfoCache->GetInfo(nullptr, savePath_, GAMEINFO_WANTSIZE); ginfo->Delete(); @@ -408,15 +468,19 @@ void SavedataBrowser::SetSortOption(SavedataSortOption opt) { if (gameList_) { SortedLinearLayout *gl = static_cast(gameList_); if (sortOption_ == SavedataSortOption::FILENAME) { - gl->SetCompare(&ByFilename, &SortDone); + gl->SetCompare(&PrepFilename, &ByFilename); } else if (sortOption_ == SavedataSortOption::SIZE) { - gl->SetCompare(&BySize, &SortDone); + gl->SetCompare(&PrepSize, &BySize); } else if (sortOption_ == SavedataSortOption::DATE) { - gl->SetCompare(&ByDate, &SortDone); + gl->SetCompare(&PrepDate, &ByDate); } } } +void SavedataBrowser::PrepFilename(UI::View *v) { + // Nothing needed. +} + bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); @@ -424,61 +488,42 @@ bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) { return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } -static time_t GetTotalSize(const SavedataButton *b) { - auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); - std::string errorString; - switch (Identify_File(fileLoader.get(), &errorString)) { - case IdentifiedFileType::PSP_PBP_DIRECTORY: - case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: - return File::ComputeRecursiveDirectorySize(ResolvePBPDirectory(b->GamePath())); - default: - return fileLoader->FileSize(); - } +void SavedataBrowser::PrepSize(UI::View *v) { + SavedataButton *b = static_cast(v); + b->UpdateTotalSize(); } bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); + const uint64_t size1 = b1->GetTotalSize(); + const uint64_t size2 = b2->GetTotalSize(); - if (GetTotalSize(b1) > GetTotalSize(b2)) + if (size1 > size2) return true; - else if (GetTotalSize(b1) < GetTotalSize(b2)) + else if (size1 < size2) return false; return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } -static time_t GetDateSeconds(const SavedataButton *b) { - auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); - tm datetm; - bool success; - std::string errorString; - if (Identify_File(fileLoader.get(), &errorString) == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { - success = File::GetModifTime(b->GamePath() / "PARAM.SFO", datetm); - } else { - success = File::GetModifTime(b->GamePath(), datetm); - } - - if (success) { - return mktime(&datetm); - } - return (time_t)0; +void SavedataBrowser::PrepDate(UI::View *v) { + SavedataButton *b = static_cast(v); + b->UpdateDateSeconds(); } bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); + const int64_t time1 = b1->GetDateSeconds(); + const int64_t time2 = b2->GetDateSeconds(); - if (GetDateSeconds(b1) > GetDateSeconds(b2)) + if (time1 > time2) return true; - if (GetDateSeconds(b1) < GetDateSeconds(b2)) + if (time1 < time2) return false; return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } -bool SavedataBrowser::SortDone() { - return true; -} - void SavedataBrowser::Refresh() { using namespace UI; diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index b9d057d025..1f9509e687 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -46,10 +46,12 @@ public: UI::Event OnChoice; private: + static void PrepFilename(UI::View *); + static void PrepSize(UI::View *); + static void PrepDate(UI::View *); static bool ByFilename(const UI::View *, const UI::View *); static bool BySize(const UI::View *, const UI::View *); static bool ByDate(const UI::View *, const UI::View *); - static bool SortDone(); void Refresh(); UI::EventReturn SavedataButtonClick(UI::EventParams &e);