diff --git a/src/apps/haikudepot/HaikuDepotConstants.h b/src/apps/haikudepot/HaikuDepotConstants.h index 0e1e606b50..c0c535735a 100644 --- a/src/apps/haikudepot/HaikuDepotConstants.h +++ b/src/apps/haikudepot/HaikuDepotConstants.h @@ -15,7 +15,6 @@ enum { MSG_CLIENT_TOO_OLD = 'oldc', MSG_NETWORK_TRANSPORT_ERROR = 'nett', MSG_SERVER_ERROR = 'svre', - MSG_SERVER_DATA_CHANGED = 'svdc', MSG_ALERT_SIMPLE_ERROR = 'nser', MSG_DID_ADD_USER_RATING = 'adur', MSG_DID_UPDATE_USER_RATING = 'upur', @@ -29,6 +28,9 @@ enum { MSG_PKG_INSTALL = 'pkgi', MSG_PKG_UNINSTALL = 'pkgu', MSG_PKG_OPEN = 'pkgo', + MSG_PKG_CACHE_SCREENSHOT = 'pcsc', + MSG_PKG_POPULATE_CHANGELOG = 'pchl', + MSG_PKG_POPULATE_USER_RATINGS = 'purg', MSG_SHOW_ALL_PACKAGES_TAB = 'sapt' }; diff --git a/src/apps/haikudepot/model/Model.cpp b/src/apps/haikudepot/model/Model.cpp index 06fdbb68f0..99dd4f07ab 100644 --- a/src/apps/haikudepot/model/Model.cpp +++ b/src/apps/haikudepot/model/Model.cpp @@ -530,6 +530,10 @@ bool Model::CanPopulatePackage(const PackageInfoRef& package) { const BString depotName = PackageUtils::DepotName(package); + + if (depotName == SINGLE_PACKAGE_DEPOT_NAME) + return false; + const DepotInfoRef& depot = DepotForName(depotName); if (!depot.IsSet()) diff --git a/src/apps/haikudepot/model/ScreenshotCoordinate.cpp b/src/apps/haikudepot/model/ScreenshotCoordinate.cpp index ad055e2cc7..1f015294c8 100644 --- a/src/apps/haikudepot/model/ScreenshotCoordinate.cpp +++ b/src/apps/haikudepot/model/ScreenshotCoordinate.cpp @@ -22,6 +22,15 @@ ScreenshotCoordinate::ScreenshotCoordinate() } +ScreenshotCoordinate::ScreenshotCoordinate(const ScreenshotCoordinate& other) + : + fCode(other.fCode), + fWidth(other.fWidth), + fHeight(other.fHeight) +{ +} + + ScreenshotCoordinate::ScreenshotCoordinate(const BMessage* from) { if (from->FindString(kKeyCode, &fCode) != B_OK) @@ -75,6 +84,16 @@ ScreenshotCoordinate::IsValid() const } +ScreenshotCoordinate& +ScreenshotCoordinate::operator=(const ScreenshotCoordinate& other) +{ + fCode = other.fCode; + fHeight = other.fHeight; + fWidth = other.fWidth; + return *this; +} + + bool ScreenshotCoordinate::operator==(const ScreenshotCoordinate& other) const { @@ -82,6 +101,13 @@ ScreenshotCoordinate::operator==(const ScreenshotCoordinate& other) const } +bool +ScreenshotCoordinate::operator!=(const ScreenshotCoordinate& other) const +{ + return !(*this == other); +} + + const BString ScreenshotCoordinate::Key() const { diff --git a/src/apps/haikudepot/model/ScreenshotCoordinate.h b/src/apps/haikudepot/model/ScreenshotCoordinate.h index ad2526c57e..884603fd51 100644 --- a/src/apps/haikudepot/model/ScreenshotCoordinate.h +++ b/src/apps/haikudepot/model/ScreenshotCoordinate.h @@ -19,6 +19,7 @@ class ScreenshotCoordinate : public BArchivable { public: ScreenshotCoordinate(const BMessage* from); ScreenshotCoordinate(BString code, uint32 width, uint32 height); + ScreenshotCoordinate(const ScreenshotCoordinate& other); ScreenshotCoordinate(); virtual ~ScreenshotCoordinate(); @@ -26,7 +27,10 @@ public: uint32 Width() const; uint32 Height() const; + ScreenshotCoordinate& + operator=(const ScreenshotCoordinate& other); bool operator==(const ScreenshotCoordinate& other) const; + bool operator!=(const ScreenshotCoordinate& other) const; bool IsValid() const; const BString Key() const; diff --git a/src/apps/haikudepot/packagemanagement/PackageAction.cpp b/src/apps/haikudepot/packagemanagement/PackageAction.cpp index b0a6a27349..f887ec1c87 100644 --- a/src/apps/haikudepot/packagemanagement/PackageAction.cpp +++ b/src/apps/haikudepot/packagemanagement/PackageAction.cpp @@ -16,6 +16,10 @@ static const char* const kKeyTitle = "title"; static const char* const kKeyDeskbarLink = "deskbar_link"; +static const char* const kKeyScreenshotCoordinates = "screenshot_coordinates"; + + +// #pragma mark - PackageAction /*! An abstract superclass of the various sorts of package actions which can be @@ -84,6 +88,9 @@ PackageAction::Archive(BMessage* into, bool deep) const } +// #pragma mark - UninstallPackageAction + + UninstallPackageAction::UninstallPackageAction(const BString& packageName, const BString& packageTitle) : @@ -113,6 +120,9 @@ UninstallPackageAction::MessageWhat() const } +// #pragma mark - InstallPackageAction + + InstallPackageAction::InstallPackageAction(const BString& packageName, const BString& packageTitle) : @@ -142,6 +152,9 @@ InstallPackageAction::MessageWhat() const } +// #pragma mark - OpenPackageAction + + OpenPackageAction::OpenPackageAction(const BString& packageName, const DeskbarLink& deskbarLink) : PackageAction("Open", packageName), @@ -197,3 +210,120 @@ OpenPackageAction::Archive(BMessage* into, bool deep) const return result; } + + +// #pragma mark - CacheScreenshotPackageAction + + +CacheScreenshotPackageAction::CacheScreenshotPackageAction(const BString& packageName, + const ScreenshotCoordinate& screenshotCoordinate) + : + PackageAction("Screenshot", packageName), + fScreenshotCoordinate(screenshotCoordinate) +{ +} + + +CacheScreenshotPackageAction::CacheScreenshotPackageAction(const BMessage* from) + : + PackageAction(from) +{ + BMessage screenshotCoordinateMessage; + if (from->FindMessage(kKeyScreenshotCoordinates, &screenshotCoordinateMessage) == B_OK) + fScreenshotCoordinate = ScreenshotCoordinate(&screenshotCoordinateMessage); + else + HDFATAL("missing key [%s]", kKeyScreenshotCoordinates); +} + + +CacheScreenshotPackageAction::~CacheScreenshotPackageAction() +{ +} + + +const uint32 +CacheScreenshotPackageAction::MessageWhat() const +{ + return MSG_PKG_CACHE_SCREENSHOT; +} + + +ScreenshotCoordinate +CacheScreenshotPackageAction::Coordinate() const +{ + return fScreenshotCoordinate; +} + + +status_t +CacheScreenshotPackageAction::Archive(BMessage* into, bool deep) const +{ + status_t result = PackageAction::Archive(into, deep); + + if (result == B_OK) { + BMessage screenshotCoordinateMessage; + result = fScreenshotCoordinate.Archive(&screenshotCoordinateMessage); + if (result == B_OK) + result = into->AddMessage(kKeyScreenshotCoordinates, &screenshotCoordinateMessage); + } + + return result; +} + + +// #pragma mark - PopulateChangelogPackageAction + + +PopulateChangelogPackageAction::PopulateChangelogPackageAction(const BString& packageName) + : + PackageAction("Populate Changelog", packageName) +{ +} + + +PopulateChangelogPackageAction::PopulateChangelogPackageAction(const BMessage* from) + : + PackageAction(from) +{ +} + + +PopulateChangelogPackageAction::~PopulateChangelogPackageAction() +{ +} + + +const uint32 +PopulateChangelogPackageAction::MessageWhat() const +{ + return MSG_PKG_POPULATE_CHANGELOG; +} + + +// #pragma mark - PopulateUserRatingsPackageAction + + +PopulateUserRatingsPackageAction::PopulateUserRatingsPackageAction(const BString& packageName) + : + PackageAction("Populate User Ratings", packageName) +{ +} + + +PopulateUserRatingsPackageAction::PopulateUserRatingsPackageAction(const BMessage* from) + : + PackageAction(from) +{ +} + + +PopulateUserRatingsPackageAction::~PopulateUserRatingsPackageAction() +{ +} + + +const uint32 +PopulateUserRatingsPackageAction::MessageWhat() const +{ + return MSG_PKG_POPULATE_USER_RATINGS; +} diff --git a/src/apps/haikudepot/packagemanagement/PackageAction.h b/src/apps/haikudepot/packagemanagement/PackageAction.h index 726d2496b9..f6a9c9f7ee 100644 --- a/src/apps/haikudepot/packagemanagement/PackageAction.h +++ b/src/apps/haikudepot/packagemanagement/PackageAction.h @@ -10,6 +10,7 @@ #include #include "DeskbarLink.h" +#include "ScreenshotCoordinate.h" class PackageAction : public BReferenceable, public BArchivable @@ -80,4 +81,44 @@ private: }; +class CacheScreenshotPackageAction : public PackageAction { +public: + CacheScreenshotPackageAction(const BString& packageName, + const ScreenshotCoordinate& screenshotCoordinate); + CacheScreenshotPackageAction(const BMessage* from); + ~CacheScreenshotPackageAction(); + + virtual const uint32 MessageWhat() const; + + ScreenshotCoordinate + Coordinate() const; + + virtual status_t Archive(BMessage* into, bool deep = true) const; + +private: + ScreenshotCoordinate + fScreenshotCoordinate; +}; + + +class PopulateChangelogPackageAction : public PackageAction { +public: + PopulateChangelogPackageAction(const BString& packageName); + PopulateChangelogPackageAction(const BMessage* from); + virtual ~PopulateChangelogPackageAction(); + + virtual const uint32 MessageWhat() const; +}; + + +class PopulateUserRatingsPackageAction : public PackageAction { +public: + PopulateUserRatingsPackageAction(const BString& packageName); + PopulateUserRatingsPackageAction(const BMessage* from); + virtual ~PopulateUserRatingsPackageAction(); + + virtual const uint32 MessageWhat() const; +}; + + #endif // PACKAGE_ACTION_H diff --git a/src/apps/haikudepot/process/ProcessCoordinator.h b/src/apps/haikudepot/process/ProcessCoordinator.h index e833e2427e..0707229b0c 100644 --- a/src/apps/haikudepot/process/ProcessCoordinator.h +++ b/src/apps/haikudepot/process/ProcessCoordinator.h @@ -67,16 +67,6 @@ public: }; -/*! Classes implementing this 'interface' are able to consume process - coordinators. This may be in order to run them. -*/ - -class ProcessCoordinatorConsumer { -public: - virtual void Consume(ProcessCoordinator *item) = 0; -}; - - /*! It is possible to create a number of ProcessNodes (themselves associated with AbstractProcess-s) that may have dependencies (predecessors and successors) and then an instance of this class is able to coordinate the diff --git a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp index ce7315b273..f955956f35 100644 --- a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp +++ b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp @@ -136,28 +136,11 @@ ProcessCoordinatorFactory::CreateBulkLoadCoordinator(Model* model, bool forceLoc } -/*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::CacheScreenshotCoordinator(Model* model, - ScreenshotCoordinate& screenshotCoordinate) -{ - return _CreateSingleProcessCoordinator("CacheScreenshot", - new CacheScreenshotProcess(model, screenshotCoordinate)); -} - - -/*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(Model* model, const BString& packageName) -{ - return _CreateSingleProcessCoordinator("PopulatePkgChangelog", - new PopulatePkgChangelogFromServerProcess(packageName, model)); -} - - /*static*/ ProcessCoordinator* ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, const BString& packageName) { - return _CreateSingleProcessCoordinator("PopulatePkgUserRatings", + return _CreateSingleProcessCoordinator("PopulatePkgUserRatings", NULL, new PopulatePkgUserRatingsFromServerProcess(packageName, model)); } @@ -166,12 +149,8 @@ ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator(Model* model, ProcessCoordinatorFactory::CreateInstallPackageActionCoordinator(Model* model, const InstallPackageAction& action) { - ProcessCoordinator* processCoordinator - = new ProcessCoordinator("InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - AbstractProcessNode* processNode - = new ThreadedProcessNode(new InstallPackageProcess(action.PackageName(), model), 10); - processCoordinator->AddNode(processNode); - return processCoordinator; + return _CreateSingleProcessCoordinator("InstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE), + new InstallPackageProcess(action.PackageName(), model)); } @@ -179,12 +158,9 @@ ProcessCoordinatorFactory::CreateInstallPackageActionCoordinator(Model* model, ProcessCoordinatorFactory::CreateUninstallPackageActionCoordinator(Model* model, const UninstallPackageAction& action) { - ProcessCoordinator* processCoordinator - = new ProcessCoordinator("UninstallPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - AbstractProcessNode* processNode - = new ThreadedProcessNode(new UninstallPackageProcess(action.PackageName(), model), 10); - processCoordinator->AddNode(processNode); - return processCoordinator; + return _CreateSingleProcessCoordinator("UninstallPackage", + new BMessage(MSG_PACKAGE_ACTION_DONE), + new UninstallPackageProcess(action.PackageName(), model)); } @@ -192,12 +168,37 @@ ProcessCoordinatorFactory::CreateUninstallPackageActionCoordinator(Model* model, ProcessCoordinatorFactory::CreateOpenPackageActionCoordinator(Model* model, const OpenPackageAction& action) { - ProcessCoordinator* processCoordinator - = new ProcessCoordinator("OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE)); - AbstractProcessNode* processNode = new ThreadedProcessNode( + return _CreateSingleProcessCoordinator("OpenPackage", new BMessage(MSG_PACKAGE_ACTION_DONE), new OpenPackageProcess(action.PackageName(), model, action.Link())); - processCoordinator->AddNode(processNode); - return processCoordinator; +} + + +/*static*/ ProcessCoordinator* +ProcessCoordinatorFactory::CreateCacheScreenshotPackageActionCoordinator(Model* model, + const CacheScreenshotPackageAction& action) +{ + return _CreateSingleProcessCoordinator("CacheScreenshot", new BMessage(MSG_PACKAGE_ACTION_DONE), + new CacheScreenshotProcess(model, action.Coordinate())); +} + + +/*static*/ ProcessCoordinator* +ProcessCoordinatorFactory::CreatePopulateChangelogPackageActionCoordinator(Model* model, + const PopulateChangelogPackageAction& action) +{ + return _CreateSingleProcessCoordinator("PopulatePkgChangelog", + new BMessage(MSG_PACKAGE_ACTION_DONE), + new PopulatePkgChangelogFromServerProcess(action.PackageName(), model)); +} + + +/*static*/ ProcessCoordinator* +ProcessCoordinatorFactory::CreatePopulateUserRatingsPackageActionCoordinator(Model* model, + const PopulateUserRatingsPackageAction& action) +{ + return _CreateSingleProcessCoordinator("PopulatePkgUserRatings", + new BMessage(MSG_PACKAGE_ACTION_DONE), + new PopulatePkgUserRatingsFromServerProcess(action.PackageName(), model)); } @@ -225,10 +226,10 @@ ProcessCoordinatorFactory::_CalculateServerProcessOptions() /*static*/ ProcessCoordinator* -ProcessCoordinatorFactory::_CreateSingleProcessCoordinator(const char* name, +ProcessCoordinatorFactory::_CreateSingleProcessCoordinator(const char* name, BMessage* message, AbstractProcess* process) { - ProcessCoordinator* processCoordinator = new ProcessCoordinator(name); + ProcessCoordinator* processCoordinator = new ProcessCoordinator(name, message); AbstractProcessNode* cacheScreenshotNode = new ThreadedProcessNode(process); processCoordinator->AddNode(cacheScreenshotNode); return processCoordinator; diff --git a/src/apps/haikudepot/process/ProcessCoordinatorFactory.h b/src/apps/haikudepot/process/ProcessCoordinatorFactory.h index a6b16aec29..2074098ae9 100644 --- a/src/apps/haikudepot/process/ProcessCoordinatorFactory.h +++ b/src/apps/haikudepot/process/ProcessCoordinatorFactory.h @@ -33,12 +33,6 @@ public: UserDetailVerifierListener* userDetailVerifierListener, Model* model); - static ProcessCoordinator* CacheScreenshotCoordinator( - Model* model, ScreenshotCoordinate& screenshotCoordinate); - - static ProcessCoordinator* PopulatePkgChangelogCoordinator(Model* model, - const BString& packageName); - static ProcessCoordinator* PopulatePkgUserRatingsCoordinator(Model* model, const BString& packageName); @@ -51,12 +45,20 @@ public: static ProcessCoordinator* CreateOpenPackageActionCoordinator(Model* model, const OpenPackageAction& action); + static ProcessCoordinator* CreateCacheScreenshotPackageActionCoordinator(Model* model, + const CacheScreenshotPackageAction& action); + + static ProcessCoordinator* CreatePopulateChangelogPackageActionCoordinator(Model* model, + const PopulateChangelogPackageAction& action); + + static ProcessCoordinator* CreatePopulateUserRatingsPackageActionCoordinator(Model* model, + const PopulateUserRatingsPackageAction& action); + private: static uint32 _CalculateServerProcessOptions(); - static ProcessCoordinator* _CreateSingleProcessCoordinator(const char* name, + static ProcessCoordinator* _CreateSingleProcessCoordinator(const char* name, BMessage* message, AbstractProcess *process); - }; #endif // PROCESS_COORDINATOR_FACTORY_H diff --git a/src/apps/haikudepot/server/CacheScreenshotProcess.cpp b/src/apps/haikudepot/server/CacheScreenshotProcess.cpp index a5c18b3402..0d4145be53 100644 --- a/src/apps/haikudepot/server/CacheScreenshotProcess.cpp +++ b/src/apps/haikudepot/server/CacheScreenshotProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025, Andrew Lindesay . + * Copyright 2023-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "CacheScreenshotProcess.h" @@ -15,8 +15,8 @@ #define B_TRANSLATION_CONTEXT "CacheScreenshotProcess" -CacheScreenshotProcess::CacheScreenshotProcess(Model *model, - ScreenshotCoordinate& screenshotCoordinate) +CacheScreenshotProcess::CacheScreenshotProcess(Model* model, + const ScreenshotCoordinate& screenshotCoordinate) : fModel(model), fScreenshotCoordinate(screenshotCoordinate) diff --git a/src/apps/haikudepot/server/CacheScreenshotProcess.h b/src/apps/haikudepot/server/CacheScreenshotProcess.h index 1fafb6cf21..7875420a56 100644 --- a/src/apps/haikudepot/server/CacheScreenshotProcess.h +++ b/src/apps/haikudepot/server/CacheScreenshotProcess.h @@ -1,5 +1,5 @@ /* - * Copyright 2023, Andrew Lindesay . + * Copyright 2023-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef CACHE_SCREENSHOT_PROCESS__H @@ -15,8 +15,8 @@ class Model; class CacheScreenshotProcess : public AbstractProcess { public: - CacheScreenshotProcess( - Model* model, ScreenshotCoordinate& screenshotCoordinate); + CacheScreenshotProcess(Model* model, + const ScreenshotCoordinate& screenshotCoordinate); virtual ~CacheScreenshotProcess(); const char* Name() const; diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp index fcb5258b08..236652c4cf 100644 --- a/src/apps/haikudepot/ui/App.cpp +++ b/src/apps/haikudepot/ui/App.cpp @@ -137,7 +137,11 @@ App::MessageReceived(BMessage* message) _AlertSimpleError(message); break; - case MSG_SERVER_DATA_CHANGED: + case MSG_PKG_POPULATE_USER_RATINGS: + // This will come from the `RatePackageWindow` when somebody has + // modified a user rating in the UI. The main window and trigger + // a background process to re-load the user rating data and then + // show it. fMainWindow->PostMessage(message); break; diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index 6970cb783a..164462b129 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -236,7 +236,7 @@ MainWindow::MainWindow(const BMessage& settings) fFilterView = new FilterView(); fFeaturedPackagesView = new FeaturedPackagesView(fModel); fPackageListView = new PackageListView(&fModel); - fPackageInfoView = new PackageInfoView(&fModel, this); + fPackageInfoView = new PackageInfoView(&fModel); fSplitView = new BSplitView(B_VERTICAL, 5.0f); @@ -329,7 +329,7 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef package) fPackageInfoListener = PackageInfoListenerRef(new MainWindowPackageInfoListener(this), true); fFilterView = new FilterView(); - fPackageInfoView = new PackageInfoView(&fModel, this); + fPackageInfoView = new PackageInfoView(&fModel); fWorkStatusView = new WorkStatusView("work status"); BLayoutBuilder::Group<>(this, B_VERTICAL) @@ -580,23 +580,6 @@ MainWindow::MessageReceived(BMessage* message) break; } - // this may be triggered by, for example, a user rating being added - // or having been altered. - case MSG_SERVER_DATA_CHANGED: - { - BString name; - if (message->FindString(shared_message_keys::kKeyPackageName, &name) == B_OK) { - if (fPackageInfoView->Package()->Name() == name) { - _PopulatePackageAsync(true); - } else { - HDDEBUG("pkg [%s] is updated on the server, but is not selected so will not be " - "updated.", - name.String()); - } - } - break; - } - case MSG_INCREMENT_VIEW_COUNTER: _HandleIncrementViewCounter(message); break; @@ -688,6 +671,36 @@ MainWindow::MessageReceived(BMessage* message) break; } + case MSG_PKG_CACHE_SCREENSHOT: + { + CacheScreenshotPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreateCacheScreenshotPackageActionCoordinator(&fModel, + action); + _AddProcessCoordinator(coordinator); + break; + } + + case MSG_PKG_POPULATE_CHANGELOG: + { + PopulateChangelogPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreatePopulateChangelogPackageActionCoordinator( + &fModel, action); + _AddProcessCoordinator(coordinator); + break; + } + + case MSG_PKG_POPULATE_USER_RATINGS: + { + PopulateUserRatingsPackageAction action(message); + ProcessCoordinator* coordinator + = ProcessCoordinatorFactory::CreatePopulateUserRatingsPackageActionCoordinator( + &fModel, action); + _AddProcessCoordinator(coordinator); + break; + } + case MSG_PKG_OPEN: { OpenPackageAction action(message); @@ -795,13 +808,6 @@ MainWindow::StoreSettings(BMessage& settings) } -void -MainWindow::Consume(ProcessCoordinator* item) -{ - _AddProcessCoordinator(item); -} - - /*! This method is invoked in the situation that a package changes in the model. The events are processed into a `BMessage` which is then posted to the @@ -1310,8 +1316,6 @@ MainWindow::_AdoptPackage(const PackageInfoRef& package) if (fPackageListView != NULL) fPackageListView->SelectPackage(package); } - - _PopulatePackageAsync(false); } @@ -1511,62 +1515,6 @@ MainWindow::_HandleWorkStatusChangeMessageReceived(const BMessage* message) } -/*! Initially only superficial data is loaded from the server into the data - model of the packages. When the package is viewed, additional data needs - to be populated including ratings. - - This method will cause the package to have its data refreshed from - the server application. The refresh happens in the background; this method - is asynchronous. -*/ - -void -MainWindow::_PopulatePackageAsync(bool forcePopulate) -{ - const PackageInfoRef package = fPackageInfoView->Package(); - - if (!fModel.CanPopulatePackage(package)) - return; - - const char* packageNameStr = package->Name().String(); - - PackageLocalizedTextRef localized = package->LocalizedText(); - bool networkAvailable = ServerHelper::IsNetworkAvailable(); - - if (localized.IsSet()) { - if (forcePopulate || localized->Changelog().IsEmpty()) { - if (localized->HasChangelog()) { - if (networkAvailable) { - _AddProcessCoordinator( - ProcessCoordinatorFactory::PopulatePkgChangelogCoordinator(&fModel, - package->Name())); - HDINFO("pkg [%s] will have changelog updated from server.", packageNameStr); - } else { - HDINFO( - "pkg [%s] will not have changelog updated from server; network unavailable", - packageNameStr); - } - } else { - HDINFO("pkg [%s] does not have a changelog -- won't try fetch it.", packageNameStr); - } - } - } - - if (forcePopulate || RatingUtils::ShouldTryPopulateUserRatings(package->UserRatingInfo())) { - if (networkAvailable) { - _AddProcessCoordinator(ProcessCoordinatorFactory::PopulatePkgUserRatingsCoordinator( - &fModel, package->Name())); - HDINFO("pkg [%s] will have user ratings updated from server.", packageNameStr); - } else { - HDINFO("pkg [%s] won't have user ratings updated from server; network unavailable", - packageNameStr); - } - } else { - HDDEBUG("pkg [%s] not have user ratings updated from server.", packageNameStr); - } -} - - void MainWindow::_OpenSettingsWindow() { diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index ced02581c2..f3430f8047 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -46,9 +46,9 @@ extern const char* const kKeyWindowSettings; }; // namespace main_window_keys -class MainWindow : - private ProcessCoordinatorConsumer, public ProcessCoordinatorListener, - public UserDetailVerifierListener, public BWindow { +class MainWindow : public ProcessCoordinatorListener, + public UserDetailVerifierListener, + public BWindow { public: MainWindow(const BMessage& settings); MainWindow(const BMessage& settings, @@ -61,9 +61,6 @@ public: void StoreSettings(BMessage& message); - // ProcessCoordinatorConsumer - virtual void Consume(ProcessCoordinator *item); - // ProcessCoordinatorListener virtual void CoordinatorChanged( ProcessCoordinatorState& coordinatorState); @@ -115,7 +112,6 @@ private: void _HandleIncrementViewCounter(const BMessage* message); void _IncrementViewCounter(const BString& packageName); - void _PopulatePackageAsync(bool forcePopulate); void _StartBulkLoad(bool force = false); void _BulkLoadCompleteReceived(status_t errorStatus); @@ -213,5 +209,4 @@ private: }; - #endif // MAIN_WINDOW_H diff --git a/src/apps/haikudepot/ui/PackageInfoView.cpp b/src/apps/haikudepot/ui/PackageInfoView.cpp index a7c4d60edd..7769e7e7ca 100644 --- a/src/apps/haikudepot/ui/PackageInfoView.cpp +++ b/src/apps/haikudepot/ui/PackageInfoView.cpp @@ -45,7 +45,6 @@ #include "PackageInfo.h" #include "PackageManager.h" #include "PackageUtils.h" -#include "ProcessCoordinatorFactory.h" #include "RatingView.h" #include "ScrollableGroupView.h" #include "ServerHelper.h" @@ -1226,35 +1225,84 @@ public: fAboutView->SetScreenshotThumbnail(bitmap); } - void SetPackage(const PackageInfoRef package, bool switchToDefaultTab) + void PopulateDataForTab(int32 index) { - if (switchToDefaultTab) - Select(TAB_ABOUT); + switch (index) { + case TAB_ABOUT: + break; + case TAB_RATINGS: + _MaybePopulateUserRatings(fPackage); + break; + case TAB_CHANGELOG: + _MaybePopulateChangelog(fPackage); + break; + case TAB_CONTENTS: + break; + default: + HDERROR("unhandled tab index for data population"); + break; + } + } + + void SetPackage(const PackageInfoRef package) + { + fPackage = package; bool enableUserRatingsTab = false; bool enableChangelogTab = false; bool enableContentsTab = false; if (package.IsSet()) { - PackageLocalizedTextRef localizedText = package->LocalizedText(); - - if (localizedText.IsSet()) - enableChangelogTab = localizedText->HasChangelog(); - + enableChangelogTab = _ShowChangelog(package); enableContentsTab = PackageUtils::IsActivatedOrLocalFile(package); - enableUserRatingsTab = _PackageCanHaveRatings(package); + enableUserRatingsTab = _ShowUserRatings(package); } TabAt(TAB_CHANGELOG)->SetEnabled(enableChangelogTab); TabAt(TAB_CONTENTS)->SetEnabled(enableContentsTab); TabAt(TAB_RATINGS)->SetEnabled(enableUserRatingsTab); - Invalidate(TabFrame(TAB_CHANGELOG)); - Invalidate(TabFrame(TAB_CONTENTS)); fAboutView->SetPackage(package); fUserRatingsView->SetPackage(package); fChangelogView->SetPackage(package); fContentsView->SetPackage(package); + + int32 currentTab = Selection(); + int32 futureTab = currentTab; + + switch (futureTab) { + case TAB_ABOUT: + break; + case TAB_RATINGS: + if (!enableUserRatingsTab) + futureTab = TAB_ABOUT; + break; + case TAB_CHANGELOG: + if (!enableChangelogTab) + futureTab = TAB_ABOUT; + break; + case TAB_CONTENTS: + if (!enableContentsTab) + futureTab = TAB_ABOUT; + break; + default: + HDERROR("unhandled tab index"); + futureTab = TAB_ABOUT; + break; + } + + if (currentTab != futureTab) + Select(futureTab); + else + PopulateDataForTab(currentTab); + } + + /*! This is overridden so that data can be loaded as the tab is selected + on-demand rather than load all the data anyway. + */ + virtual void Select(int32 index) { + BTabView::Select(index); + PopulateDataForTab(index); } void Clear() @@ -1266,22 +1314,78 @@ public: } private: - /*! It is only possible for a package to have ratings if it is associated with a server-side - repository (depot). Otherwise there will be no means to display ratings. - */ - bool _PackageCanHaveRatings(const PackageInfoRef package) + + bool _ShowUserRatings(const PackageInfoRef package) { - BString depotName = PackageUtils::DepotName(package); + if (!package.IsSet()) + return false; + return PackageUtils::IsPopulatedUserRatings(package) + || (fModel->CanPopulatePackage(package) && ServerHelper::IsNetworkAvailable() + && PackageUtils::HasUserRatings(package)); + } - if (depotName == SINGLE_PACKAGE_DEPOT_NAME) - return false; + bool _ShowChangelog(const PackageInfoRef package) { + if (!package.IsSet()) + return false; + return PackageUtils::IsPopulatedChangelog(package) + || (fModel->CanPopulatePackage(package) && ServerHelper::IsNetworkAvailable() + && PackageUtils::HasChangelog(package)); + } - const DepotInfoRef depotInfo = fModel->DepotForName(depotName); + /*! Returns true if the changelog should be available. + */ + void _MaybePopulateChangelog(const PackageInfoRef package) { + if (!package.IsSet()) + return; - if (depotInfo.IsSet()) - return !depotInfo->WebAppRepositoryCode().IsEmpty(); + if (PackageUtils::IsPopulatedChangelog(package)) + return; - return false; + if (!fModel->CanPopulatePackage(package)) + return; + + if (!ServerHelper::IsNetworkAvailable()) { + HDINFO("will skip populating changelog for [%s] as no network is available", + package->Name().String()); + return; + } + + if (!PackageUtils::HasChangelog(package)) + return; + + // This will case a background task to start which will fetch the changelog + // from the server and populate it into the package data stored in the model. + // The correct view will be updated when the data arrives to present. + PopulateChangelogPackageAction action(package->Name()); + BMessage message = action.Message(); + Window()->PostMessage(&message); + } + + void _MaybePopulateUserRatings(const PackageInfoRef package) { + if (!package.IsSet()) + return; + + if (PackageUtils::IsPopulatedUserRatings(package)) + return; + + if (!fModel->CanPopulatePackage(package)) + return; + + if (!ServerHelper::IsNetworkAvailable()) { + HDINFO("will skip populating user ratings for [%s] as no network is available", + package->Name().String()); + return; + } + + if (!PackageUtils::HasUserRatings(package)) + return; + + // This will case a background task to start which will fetch the user ratings + // from the server and populate it into the package data stored in the model. + // The correct view will be updated when the data arrives to present. + PopulateUserRatingsPackageAction action(package->Name()); + BMessage message = action.Message(); + Window()->PostMessage(&message); } private: @@ -1290,18 +1394,17 @@ private: UserRatingsView* fUserRatingsView; ChangelogView* fChangelogView; ContentsView* fContentsView; + PackageInfoRef fPackage; }; // #pragma mark - PackageInfoView -PackageInfoView::PackageInfoView(Model* model, - ProcessCoordinatorConsumer* processCoordinatorConsumer) +PackageInfoView::PackageInfoView(Model* model) : BView("package info view", 0), - fModel(model), - fProcessCoordinatorConsumer(processCoordinatorConsumer) + fModel(model) { fCardLayout = new BCardLayout(); SetLayout(fCardLayout); @@ -1362,23 +1465,9 @@ PackageInfoView::SetPackage(const PackageInfoRef& packageRef) return; } - bool switchToDefaultTab = true; - if (fPackage == packageRef) { - // When asked to display the already showing package ref, - // don't switch to the default tab. - switchToDefaultTab = false; - } else if (fPackage.IsSet() && packageRef.IsSet() && fPackage->Name() == packageRef->Name()) { - // When asked to display a different PackageInfo instance, - // but it has the same package title as the already showing - // instance, this probably means there was a repository - // refresh and we are in fact still requested to show the - // same package as before the refresh. - switchToDefaultTab = false; - } - fTitleView->SetPackage(packageRef); fPackageActionView->SetPackage(packageRef); - fPagesView->SetPackage(packageRef, switchToDefaultTab); + fPagesView->SetPackage(packageRef); _SetPackageScreenshotThumb(packageRef); @@ -1411,7 +1500,7 @@ PackageInfoView::_HandlePackageChanged(const PackageInfoChangeEvent& event) if ((changes & PKG_CHANGED_LOCALIZED_TEXT) != 0 || (changes & PKG_CHANGED_SCREENSHOTS) != 0 || (changes & PKG_CHANGED_RATINGS) != 0 || (changes & PKG_CHANGED_LOCAL_INFO) != 0) { - fPagesView->SetPackage(package, false); + fPagesView->SetPackage(package); } if ((changes & PKG_CHANGED_LOCALIZED_TEXT) != 0 || (changes & PKG_CHANGED_RATINGS) != 0) @@ -1443,7 +1532,6 @@ PackageInfoView::HandlePackagesChanged(const std::vector the background. A message will come through later once it is cached and ready to load. */ - void PackageInfoView::_SetPackageScreenshotThumb(const PackageInfoRef& package) { @@ -1467,9 +1555,9 @@ PackageInfoView::_SetPackageScreenshotThumb(const PackageInfoRef& package) HDINFO("screenshot won't be cached [%s] -- network unavailable", packageNameCStr); } else { HDDEBUG("screenshot is not cached [%s] -- will cache it", packageNameCStr); - ProcessCoordinator* processCoordinator - = ProcessCoordinatorFactory::CacheScreenshotCoordinator(fModel, desiredCoordinate); - fProcessCoordinatorConsumer->Consume(processCoordinator); + CacheScreenshotPackageAction action(package->Name(), desiredCoordinate); + BMessage message = action.Message(); + Window()->PostMessage(&message); } } else { HDDEBUG("no screenshot for pkg [%s]", packageNameCStr); diff --git a/src/apps/haikudepot/ui/PackageInfoView.h b/src/apps/haikudepot/ui/PackageInfoView.h index 67b12f7d51..31f5771744 100644 --- a/src/apps/haikudepot/ui/PackageInfoView.h +++ b/src/apps/haikudepot/ui/PackageInfoView.h @@ -13,7 +13,6 @@ #include "Model.h" #include "PackageInfo.h" #include "PackageInfoListener.h" -#include "ProcessCoordinator.h" class BCardLayout; @@ -31,9 +30,7 @@ enum { class PackageInfoView : public BView { public: - PackageInfoView(Model* model, - ProcessCoordinatorConsumer* - processCoordinatorConsumer); + PackageInfoView(Model* model); virtual ~PackageInfoView(); virtual void AttachedToWindow(); @@ -68,8 +65,6 @@ private: PackageInfoRef fPackage; OnePackageMessagePackageListener* fPackageListener; - ProcessCoordinatorConsumer* - fProcessCoordinatorConsumer; }; #endif // PACKAGE_INFO_VIEW_H diff --git a/src/apps/haikudepot/ui/RatePackageWindow.cpp b/src/apps/haikudepot/ui/RatePackageWindow.cpp index a7f0d7566a..c164083c20 100644 --- a/src/apps/haikudepot/ui/RatePackageWindow.cpp +++ b/src/apps/haikudepot/ui/RatePackageWindow.cpp @@ -26,6 +26,7 @@ #include "LanguageMenuUtils.h" #include "Logger.h" #include "MarkupParser.h" +#include "PackageAction.h" #include "PackageUtils.h" #include "RatingView.h" #include "ServerHelper.h" @@ -371,8 +372,8 @@ RatePackageWindow::MessageReceived(BMessage* message) void RatePackageWindow::_RefreshPackageData() { - BMessage message(MSG_SERVER_DATA_CHANGED); - message.AddString(shared_message_keys::kKeyPackageName, fPackage->Name()); + PopulateUserRatingsPackageAction action(fPackage->Name()); + BMessage message = action.Message(); be_app->PostMessage(&message); } diff --git a/src/apps/haikudepot/util/PackageUtils.cpp b/src/apps/haikudepot/util/PackageUtils.cpp index a8051cf06c..df8e404e50 100644 --- a/src/apps/haikudepot/util/PackageUtils.cpp +++ b/src/apps/haikudepot/util/PackageUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025, Andrew Lindesay . + * Copyright 2024-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -52,6 +52,66 @@ PackageUtils::Summary(const PackageInfoRef& package, BString& summary) } +/*static*/ bool +PackageUtils::HasChangelog(const PackageInfoRef& package) +{ + if (package.IsSet()) { + PackageLocalizedTextRef localizedText = package->LocalizedText(); + + if (localizedText.IsSet()) + return localizedText->HasChangelog(); + } + + return false; +} + + +/*static*/ bool +PackageUtils::IsPopulatedChangelog(const PackageInfoRef& package) +{ + if (package.IsSet()) { + PackageLocalizedTextRef localizedText = package->LocalizedText(); + + if (localizedText.IsSet()) + return !localizedText->Changelog().IsEmpty(); + } + + return false; +} + + +/*static*/ bool +PackageUtils::HasUserRatings(const PackageInfoRef& package) +{ + if (package.IsSet()) { + PackageUserRatingInfoRef userRatingInfo = package->UserRatingInfo(); + + if (userRatingInfo.IsSet()) { + UserRatingSummaryRef summary = userRatingInfo->Summary(); + + if (summary.IsSet()) + return summary->RatingCount() > 0; + } + } + + return false; +} + + +/*static*/ bool +PackageUtils::IsPopulatedUserRatings(const PackageInfoRef& package) +{ + if (package.IsSet()) { + PackageUserRatingInfoRef userRatingInfo = package->UserRatingInfo(); + + if (userRatingInfo.IsSet()) + return userRatingInfo->UserRatingsPopulated(); + } + + return false; +} + + /*static*/ const BString PackageUtils::DepotName(const PackageInfoRef& package) { diff --git a/src/apps/haikudepot/util/PackageUtils.h b/src/apps/haikudepot/util/PackageUtils.h index 050e456a21..60454af8fb 100644 --- a/src/apps/haikudepot/util/PackageUtils.h +++ b/src/apps/haikudepot/util/PackageUtils.h @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025, Andrew Lindesay . + * Copyright 2024-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef PACKAGE_UTILS_H @@ -15,6 +15,12 @@ public: static void Title(const PackageInfoRef& package, BString& title); static void Summary(const PackageInfoRef& package, BString& summary); + static bool HasChangelog(const PackageInfoRef& package); + static bool IsPopulatedChangelog(const PackageInfoRef& package); + + static bool HasUserRatings(const PackageInfoRef& package); + static bool IsPopulatedUserRatings(const PackageInfoRef& package); + static PackageVersionRef Version(const PackageInfoRef& package); static const BString Architecture(const PackageInfoRef& package); diff --git a/src/apps/haikudepot/util/RatingUtils.cpp b/src/apps/haikudepot/util/RatingUtils.cpp index bfa3da9400..d7a07bb294 100644 --- a/src/apps/haikudepot/util/RatingUtils.cpp +++ b/src/apps/haikudepot/util/RatingUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025, Andrew Lindesay . + * Copyright 2020-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -99,26 +99,3 @@ RatingUtils::Draw(BView* target, BPoint at, float value, const BBitmap* star) target->FillRect(shadeOverRect, B_SOLID_HIGH); } } - - -/*! With the `userRatingInfo` provided, does it make sense for the application - to attempt to download the user ratings? If it looks like there are none - then it's making no sense and if it has already downloaded some then it - also does not make any sense. -*/ -/*static*/ bool -RatingUtils::ShouldTryPopulateUserRatings(PackageUserRatingInfoRef userRatingInfo) -{ - if (!userRatingInfo.IsSet()) - return true; - - UserRatingSummaryRef summary = userRatingInfo->Summary(); - - if (!summary.IsSet()) - return true; - - if (summary->RatingCount() == 0) - return false; - - return !userRatingInfo->UserRatingsPopulated(); -} diff --git a/src/apps/haikudepot/util/RatingUtils.h b/src/apps/haikudepot/util/RatingUtils.h index e7100889a8..5c68a0b69d 100644 --- a/src/apps/haikudepot/util/RatingUtils.h +++ b/src/apps/haikudepot/util/RatingUtils.h @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025, Andrew Lindesay . + * Copyright 2020-2026, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef RATING_UTILS_H @@ -36,8 +36,6 @@ public: static void Draw(BView* target, BPoint at, float value, const BBitmap* star); static void Draw(BView* target, BPoint at, float value); - - static bool ShouldTryPopulateUserRatings(PackageUserRatingInfoRef userRatingInfo); };