HaikuDepot: Increment Pkg View Counter

Closes #16814

Change-Id: Idf451628b4680fb33563dbf4817bd11049c326b5
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3803
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Andrew Lindesay 2021-03-17 00:09:05 +13:00
parent 068d41df0f
commit 133ebab62c
16 changed files with 553 additions and 23 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef HAIKU_DEPOT_CONSTANTS_H #ifndef HAIKU_DEPOT_CONSTANTS_H
@ -73,6 +73,15 @@ enum BitmapSize {
#define KEY_MAIN_SETTINGS "main_settings" #define KEY_MAIN_SETTINGS "main_settings"
#define SETTING_SHOW_AVAILABLE_PACKAGES "show available packages"
#define SETTING_SHOW_INSTALLED_PACKAGES "show installed packages"
#define SETTING_SHOW_DEVELOP_PACKAGES "show develop packages"
#define SETTING_SHOW_SOURCE_PACKAGES "show source packages"
#define SETTING_CAN_SHARE_ANONYMOUS_USER_DATA "can share anonymous usage data"
#define SETTING_PACKAGE_LIST_VIEW_MODE "packageListViewMode"
// unfortunately historical difference in casing.
// These constants reference resources in 'HaikuDepot.ref' // These constants reference resources in 'HaikuDepot.ref'
enum { enum {
RSRC_STAR_BLUE = 510, RSRC_STAR_BLUE = 510,

View File

@ -120,6 +120,7 @@ local applicationSources =
FeaturedPackagesView.cpp FeaturedPackagesView.cpp
FilterView.cpp FilterView.cpp
IconTarPtr.cpp IconTarPtr.cpp
IncrementViewCounterProcess.cpp
JobStateListener.cpp JobStateListener.cpp
LanguageModel.cpp LanguageModel.cpp
LinkView.cpp LinkView.cpp
@ -146,6 +147,7 @@ local applicationSources =
support.cpp support.cpp
ScreenshotWindow.cpp ScreenshotWindow.cpp
ScrollableGroupView.cpp ScrollableGroupView.cpp
SettingsWindow.cpp
SharedBitmap.cpp SharedBitmap.cpp
ToLatestUserUsageConditionsWindow.cpp ToLatestUserUsageConditionsWindow.cpp
UserCredentials.cpp UserCredentials.cpp

View File

@ -212,7 +212,8 @@ Model::Model()
fShowAvailablePackages(true), fShowAvailablePackages(true),
fShowInstalledPackages(true), fShowInstalledPackages(true),
fShowSourcePackages(false), fShowSourcePackages(false),
fShowDevelopPackages(false) fShowDevelopPackages(false),
fCanShareAnonymousUsageData(false)
{ {
} }
@ -436,6 +437,13 @@ Model::SetPackageListViewMode(package_list_view_mode mode)
} }
void
Model::SetCanShareAnonymousUsageData(bool value)
{
fCanShareAnonymousUsageData = value;
}
void void
Model::SetShowAvailablePackages(bool show) Model::SetShowAvailablePackages(bool show)
{ {

View File

@ -129,6 +129,9 @@ public:
void SetShowDevelopPackages(bool show); void SetShowDevelopPackages(bool show);
bool ShowDevelopPackages() const bool ShowDevelopPackages() const
{ return fShowDevelopPackages; } { return fShowDevelopPackages; }
void SetCanShareAnonymousUsageData(bool value);
bool CanShareAnonymousUsageData() const
{ return fCanShareAnonymousUsageData; }
// Retrieve package information // Retrieve package information
static const uint32 POPULATE_CACHED_RATING = 1 << 0; static const uint32 POPULATE_CACHED_RATING = 1 << 0;
@ -150,8 +153,8 @@ public:
const BString& passwordClear, const BString& passwordClear,
bool storePassword); bool storePassword);
const WebAppInterface& WebAppInterface&
GetWebAppInterface() const GetWebAppInterface()
{ return fWebAppInterface; } { return fWebAppInterface; }
status_t IconTarPath(BPath& path) const; status_t IconTarPath(BPath& path) const;
@ -205,6 +208,7 @@ private:
bool fShowInstalledPackages; bool fShowInstalledPackages;
bool fShowSourcePackages; bool fShowSourcePackages;
bool fShowDevelopPackages; bool fShowDevelopPackages;
bool fCanShareAnonymousUsageData;
LanguageModel fLanguageModel; LanguageModel fLanguageModel;
PackageIconTarRepository PackageIconTarRepository

View File

@ -453,6 +453,7 @@ PackageInfo::PackageInfo()
fFileName(), fFileName(),
fSize(0), fSize(0),
fDepotName(""), fDepotName(""),
fViewed(false),
fIsCollatingChanges(false), fIsCollatingChanges(false),
fCollatedChanges(0) fCollatedChanges(0)
{ {
@ -483,6 +484,7 @@ PackageInfo::PackageInfo(const BPackageInfo& info)
fFileName(info.FileName()), fFileName(info.FileName()),
fSize(0), // TODO: Retrieve local file size fSize(0), // TODO: Retrieve local file size
fDepotName(""), fDepotName(""),
fViewed(false),
fIsCollatingChanges(false), fIsCollatingChanges(false),
fCollatedChanges(0) fCollatedChanges(0)
{ {
@ -529,6 +531,7 @@ PackageInfo::PackageInfo(const BString& name,
fFileName(), fFileName(),
fSize(0), fSize(0),
fDepotName(""), fDepotName(""),
fViewed(false),
fIsCollatingChanges(false), fIsCollatingChanges(false),
fCollatedChanges(0) fCollatedChanges(0)
{ {
@ -561,6 +564,7 @@ PackageInfo::PackageInfo(const PackageInfo& other)
fFileName(other.fFileName), fFileName(other.fFileName),
fSize(other.fSize), fSize(other.fSize),
fDepotName(other.fDepotName), fDepotName(other.fDepotName),
fViewed(other.fViewed),
fIsCollatingChanges(false), fIsCollatingChanges(false),
fCollatedChanges(0) fCollatedChanges(0)
{ {
@ -593,6 +597,8 @@ PackageInfo::operator=(const PackageInfo& other)
fLocalFilePath = other.fLocalFilePath; fLocalFilePath = other.fLocalFilePath;
fFileName = other.fFileName; fFileName = other.fFileName;
fSize = other.fSize; fSize = other.fSize;
fDepotName = other.fDepotName;
fViewed = other.fViewed;
return *this; return *this;
} }
@ -987,6 +993,13 @@ PackageInfo::SetSize(int64 size)
} }
void
PackageInfo::SetViewed()
{
fViewed = true;
}
void void
PackageInfo::SetDepotName(const BString& depotName) PackageInfo::SetDepotName(const BString& depotName)
{ {

View File

@ -253,7 +253,8 @@ public:
{ return fName; } { return fName; }
void SetTitle(const BString& title); void SetTitle(const BString& title);
const BString& Title() const; const BString& Title() const;
const BPackageVersion& Version() const const BPackageVersion&
Version() const
{ return fVersion; } { return fVersion; }
void SetShortDescription(const BString& description); void SetShortDescription(const BString& description);
const BString& ShortDescription() const const BString& ShortDescription() const
@ -336,6 +337,10 @@ public:
int64 Size() const int64 Size() const
{ return fSize; } { return fSize; }
void SetViewed();
bool Viewed() const
{ return fViewed; }
void SetDepotName(const BString& depotName); void SetDepotName(const BString& depotName);
const BString& DepotName() const const BString& DepotName() const
{ return fDepotName; } { return fDepotName; }
@ -387,6 +392,7 @@ private:
BString fFileName; BString fFileName;
int64 fSize; int64 fSize;
BString fDepotName; BString fDepotName;
bool fViewed;
bool fIsCollatingChanges; bool fIsCollatingChanges;
uint32 fCollatedChanges; uint32 fCollatedChanges;

View File

@ -0,0 +1,119 @@
/*
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "IncrementViewCounterProcess.h"
#include <Catalog.h>
#include "Logger.h"
#include "ServerHelper.h"
#include "WebAppInterface.h"
#define ATTEMPTS 3
#define SPIN_BETWEEN_ATTEMPTS_DELAY_MI 5 * 1000 * 1000
// 5 seconds
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "IncrementViewCounterProcess"
IncrementViewCounterProcess::IncrementViewCounterProcess(
Model* model, const PackageInfoRef package)
:
fPackage(package),
fModel(model)
{
fDescription = BString(B_TRANSLATE("Recording view of \"%PackageName%\""))
.ReplaceAll("%PackageName%", fPackage->Name());
}
IncrementViewCounterProcess::~IncrementViewCounterProcess()
{
}
const char*
IncrementViewCounterProcess::Name() const
{
return "IncrementViewCounterProcess";
}
const char*
IncrementViewCounterProcess::Description() const
{
return fDescription.String();
}
status_t
IncrementViewCounterProcess::RunInternal()
{
if (!ServerHelper::IsNetworkAvailable()) {
HDINFO("no network so will not increment view counter");
return B_OK;
}
if (!fPackage.IsSet()) {
HDERROR("the package is not present to increment the view counter");
return B_ERROR;
}
DepotInfoRef depot = fModel->DepotForName(fPackage->DepotName());
if (!depot.IsSet()) {
HDERROR("the package's depot is not present to increment the view "
"counter");
return B_ERROR;
}
int32 attempts = ATTEMPTS;
status_t result;
while (attempts > 0 && !WasStopped()) {
BMessage resultEnvelope;
WebAppInterface& webAppInterface = fModel->GetWebAppInterface();
result = webAppInterface.IncrementViewCounter(fPackage, depot,
resultEnvelope);
if (result == B_OK) {
int32 errorCode = webAppInterface.ErrorCodeFromResponse(
resultEnvelope);
switch (errorCode) {
case ERROR_CODE_NONE:
HDINFO("did increment the view counter for [%s]",
fPackage->Name().String());
return result;
case ERROR_CODE_OBJECTNOTFOUND:
HDINFO("server was not able to find the package [%s]",
fPackage->Name().String());
return B_NAME_NOT_FOUND;
default:
HDERROR("a problem has arisen incrementing the view "
"counter for pkg [%s] w/ error code %" B_PRId32,
fPackage->Name().String(), errorCode);
result = B_ERROR;
break;
}
} else
HDERROR("an error has arisen incrementing the view counter");
attempts--;
_SpinBetweenAttempts();
}
return result;
}
void
IncrementViewCounterProcess::_SpinBetweenAttempts()
{
useconds_t miniSpinDelays = SPIN_BETWEEN_ATTEMPTS_DELAY_MI / 10;
for (int32 i = 0; i < 10 && !WasStopped(); i++)
usleep(miniSpinDelays);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef INCREMENT_VIEW_COUNTER_PROCESS_H
#define INCREMENT_VIEW_COUNTER_PROCESS_H
#include "AbstractProcess.h"
#include "Model.h"
#include "PackageInfo.h"
class Model;
class IncrementViewCounterProcess : public AbstractProcess {
public:
IncrementViewCounterProcess(
Model* model,
const PackageInfoRef package);
virtual ~IncrementViewCounterProcess();
const char* Name() const;
const char* Description() const;
protected:
virtual status_t RunInternal();
private:
void _SpinBetweenAttempts();
private:
BString fDescription;
PackageInfoRef fPackage;
Model* fModel;
};
#endif // INCREMENT_VIEW_COUNTER_PROCESS_H

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@ -14,6 +14,7 @@
#include "AbstractServerProcess.h" #include "AbstractServerProcess.h"
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "IncrementViewCounterProcess.h"
#include "LocalPkgDataLoadProcess.h" #include "LocalPkgDataLoadProcess.h"
#include "LocalRepositoryUpdateProcess.h" #include "LocalRepositoryUpdateProcess.h"
#include "Logger.h" #include "Logger.h"
@ -34,6 +35,21 @@
using namespace BPackageKit; using namespace BPackageKit;
/*static*/ ProcessCoordinator*
ProcessCoordinatorFactory::CreateIncrementViewCounter(
ProcessCoordinatorListener* processCoordinatorListener,
Model* model, const PackageInfoRef package)
{
ProcessCoordinator* processCoordinator = new ProcessCoordinator(
"IncrementViewCounter",
processCoordinatorListener);
ProcessNode* node = new ProcessNode(
new IncrementViewCounterProcess(model, package));
processCoordinator->AddNode(node);
return processCoordinator;
}
/*static*/ ProcessCoordinator* /*static*/ ProcessCoordinator*
ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator( ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
UserDetailVerifierListener* userDetailVerifierListener, UserDetailVerifierListener* userDetailVerifierListener,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@ -9,6 +9,8 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include "PackageInfo.h"
class Model; class Model;
class PackageInfoListener; class PackageInfoListener;
class ProcessCoordinator; class ProcessCoordinator;
@ -21,6 +23,11 @@ class UserDetailVerifierListener;
class ProcessCoordinatorFactory { class ProcessCoordinatorFactory {
public: public:
static ProcessCoordinator* CreateIncrementViewCounter(
ProcessCoordinatorListener*
processCoordinatorListener,
Model* model, const PackageInfoRef package);
static ProcessCoordinator* CreateBulkLoadCoordinator( static ProcessCoordinator* CreateBulkLoadCoordinator(
PackageInfoListener *packageInfoListener, PackageInfoListener *packageInfoListener,
ProcessCoordinatorListener* ProcessCoordinatorListener*
@ -38,4 +45,4 @@ private:
}; };
#endif // PROCESS_COORDINATOR_FACTORY_H #endif // PROCESS_COORDINATOR_FACTORY_H

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2020, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@ -758,6 +758,61 @@ WebAppInterface::AuthenticateUser(const BString& nickName,
} }
status_t
WebAppInterface::IncrementViewCounter(const PackageInfoRef package,
const DepotInfoRef depot, BMessage& message)
{
BMallocIO* requestEnvelopeData = new BMallocIO();
// BHttpRequest later takes ownership of this.
BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData);
requestEnvelopeWriter.WriteObjectStart();
_WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter,
"incrementViewCounter");
requestEnvelopeWriter.WriteObjectName("params");
requestEnvelopeWriter.WriteArrayStart();
requestEnvelopeWriter.WriteObjectStart();
requestEnvelopeWriter.WriteObjectName("architectureCode");
requestEnvelopeWriter.WriteString(package->Architecture());
requestEnvelopeWriter.WriteObjectName("repositoryCode");
requestEnvelopeWriter.WriteString(depot->WebAppRepositoryCode());
requestEnvelopeWriter.WriteObjectName("name");
requestEnvelopeWriter.WriteString(package->Name());
const BPackageVersion version = package->Version();
if (!version.Major().IsEmpty()) {
requestEnvelopeWriter.WriteObjectName("major");
requestEnvelopeWriter.WriteString(version.Major());
}
if (!version.Minor().IsEmpty()) {
requestEnvelopeWriter.WriteObjectName("minor");
requestEnvelopeWriter.WriteString(version.Minor());
}
if (!version.Micro().IsEmpty()) {
requestEnvelopeWriter.WriteObjectName("micro");
requestEnvelopeWriter.WriteString(version.Micro());
}
if (!version.PreRelease().IsEmpty()) {
requestEnvelopeWriter.WriteObjectName("preRelease");
requestEnvelopeWriter.WriteString(version.PreRelease());
}
if (version.Revision() != 0) {
requestEnvelopeWriter.WriteObjectName("revision");
requestEnvelopeWriter.WriteInteger(
static_cast<int64>(version.Revision()));
}
requestEnvelopeWriter.WriteObjectEnd();
requestEnvelopeWriter.WriteArrayEnd();
requestEnvelopeWriter.WriteObjectEnd();
return _SendJsonRequest("pkg", requestEnvelopeData,
_LengthAndSeekToZero(requestEnvelopeData), 0,
message);
}
/*! JSON-RPC invocations return a response. The response may be either /*! JSON-RPC invocations return a response. The response may be either
a result or it may be an error depending on the response structure. a result or it may be an error depending on the response structure.
If it is an error then there may be additional detail that is the If it is an error then there may be additional detail that is the

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016-2020, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2016-2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef WEB_APP_INTERFACE_H #ifndef WEB_APP_INTERFACE_H
@ -12,6 +12,7 @@
#include <String.h> #include <String.h>
#include <package/PackageVersion.h> #include <package/PackageVersion.h>
#include "PackageInfo.h"
#include "UserCredentials.h" #include "UserCredentials.h"
#include "UserDetail.h" #include "UserDetail.h"
#include "UserUsageConditions.h" #include "UserUsageConditions.h"
@ -120,6 +121,11 @@ public:
const BString& passwordClear, const BString& passwordClear,
BMessage& message); BMessage& message);
status_t IncrementViewCounter(
const PackageInfoRef package,
const DepotInfoRef depot,
BMessage& message);
static int32 ErrorCodeFromResponse( static int32 ErrorCodeFromResponse(
BMessage& responseEnvelopeMessage); BMessage& responseEnvelopeMessage);

View File

@ -47,6 +47,7 @@
#include "RatePackageWindow.h" #include "RatePackageWindow.h"
#include "support.h" #include "support.h"
#include "ScreenshotWindow.h" #include "ScreenshotWindow.h"
#include "SettingsWindow.h"
#include "ToLatestUserUsageConditionsWindow.h" #include "ToLatestUserUsageConditionsWindow.h"
#include "UserLoginWindow.h" #include "UserLoginWindow.h"
#include "UserUsageConditionsWindow.h" #include "UserUsageConditionsWindow.h"
@ -61,6 +62,7 @@ enum {
MSG_REFRESH_REPOS = 'mrrp', MSG_REFRESH_REPOS = 'mrrp',
MSG_MANAGE_REPOS = 'mmrp', MSG_MANAGE_REPOS = 'mmrp',
MSG_SOFTWARE_UPDATER = 'mswu', MSG_SOFTWARE_UPDATER = 'mswu',
MSG_SETTINGS = 'stgs',
MSG_LOG_IN = 'lgin', MSG_LOG_IN = 'lgin',
MSG_AUTHORIZATION_CHANGED = 'athc', MSG_AUTHORIZATION_CHANGED = 'athc',
MSG_CATEGORIES_LIST_CHANGED = 'clic', MSG_CATEGORIES_LIST_CHANGED = 'clic',
@ -76,7 +78,6 @@ enum {
}; };
#define KEY_ERROR_STATUS "errorStatus" #define KEY_ERROR_STATUS "errorStatus"
#define KEY_PACKAGE_LIST_VIEW_MODE "packageListViewMode"
#define TAB_PROMINENT_PACKAGES 0 #define TAB_PROMINENT_PACKAGES 0
#define TAB_ALL_PACKAGES 1 #define TAB_ALL_PACKAGES 1
@ -195,6 +196,7 @@ MainWindow::MainWindow(const BMessage& settings)
fPackageListView->LoadState(&columnSettings); fPackageListView->LoadState(&columnSettings);
_RestoreModelSettings(settings); _RestoreModelSettings(settings);
_MaybePromptCanShareAnonymousUserData(settings);
if (fModel.PackageListViewMode() == PROMINENT) if (fModel.PackageListViewMode() == PROMINENT)
fListTabs->Select(TAB_PROMINENT_PACKAGES); fListTabs->Select(TAB_PROMINENT_PACKAGES);
@ -343,6 +345,10 @@ MainWindow::MessageReceived(BMessage* message)
_OpenLoginWindow(BMessage()); _OpenLoginWindow(BMessage());
break; break;
case MSG_SETTINGS:
_OpenSettingsWindow();
break;
case MSG_LOG_OUT: case MSG_LOG_OUT:
fModel.SetNickname(""); fModel.SetNickname("");
break; break;
@ -431,8 +437,10 @@ MainWindow::MessageReceived(BMessage* message)
} }
if (!package.IsSet() || name != package->Name()) if (!package.IsSet() || name != package->Name())
debugger("unable to find the named package"); debugger("unable to find the named package");
else else {
_AdoptPackage(package); _AdoptPackage(package);
_IncrementViewCounter(package);
}
} else { } else {
_ClearPackage(); _ClearPackage();
} }
@ -577,15 +585,19 @@ MainWindow::StoreSettings(BMessage& settings) const
settings.AddMessage("column settings", &columnSettings); settings.AddMessage("column settings", &columnSettings);
settings.AddString(KEY_PACKAGE_LIST_VIEW_MODE, settings.AddString(SETTING_PACKAGE_LIST_VIEW_MODE,
main_window_package_list_view_mode_str( main_window_package_list_view_mode_str(
fModel.PackageListViewMode())); fModel.PackageListViewMode()));
settings.AddBool("show available packages", settings.AddBool(SETTING_SHOW_AVAILABLE_PACKAGES,
fModel.ShowAvailablePackages()); fModel.ShowAvailablePackages());
settings.AddBool("show installed packages", settings.AddBool(SETTING_SHOW_INSTALLED_PACKAGES,
fModel.ShowInstalledPackages()); fModel.ShowInstalledPackages());
settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); settings.AddBool(SETTING_SHOW_DEVELOP_PACKAGES,
settings.AddBool("show source packages", fModel.ShowSourcePackages()); fModel.ShowDevelopPackages());
settings.AddBool(SETTING_SHOW_SOURCE_PACKAGES,
fModel.ShowSourcePackages());
settings.AddBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
fModel.CanShareAnonymousUsageData());
} }
settings.AddString("username", fModel.Nickname()); settings.AddString("username", fModel.Nickname());
@ -627,6 +639,14 @@ MainWindow::GetModel()
void void
MainWindow::_BuildMenu(BMenuBar* menuBar) MainWindow::_BuildMenu(BMenuBar* menuBar)
{ {
BMenu* windowMenu = new BMenu(B_TRANSLATE("Window"));
windowMenu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
new BMessage(MSG_SETTINGS)));
windowMenu->AddSeparatorItem();
windowMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit" B_UTF8_ELLIPSIS),
new BMessage(B_QUIT_REQUESTED), 'Q'));
menuBar->AddItem(windowMenu);
BMenu* menu = new BMenu(B_TRANSLATE("Tools")); BMenu* menu = new BMenu(B_TRANSLATE("Tools"));
fRefreshRepositoriesItem = new BMenuItem( fRefreshRepositoriesItem = new BMenuItem(
B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS)); B_TRANSLATE("Refresh repositories"), new BMessage(MSG_REFRESH_REPOS));
@ -635,7 +655,6 @@ MainWindow::_BuildMenu(BMenuBar* menuBar)
B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS))); B_UTF8_ELLIPSIS), new BMessage(MSG_MANAGE_REPOS)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates" menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates"
B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER))); B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER)));
menuBar->AddItem(menu); menuBar->AddItem(menu);
fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories")); fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories"));
@ -756,21 +775,52 @@ void
MainWindow::_RestoreModelSettings(const BMessage& settings) MainWindow::_RestoreModelSettings(const BMessage& settings)
{ {
BString packageListViewMode; BString packageListViewMode;
if (settings.FindString(KEY_PACKAGE_LIST_VIEW_MODE, if (settings.FindString(SETTING_PACKAGE_LIST_VIEW_MODE,
&packageListViewMode) == B_OK) { &packageListViewMode) == B_OK) {
fModel.SetPackageListViewMode( fModel.SetPackageListViewMode(
main_window_str_to_package_list_view_mode(packageListViewMode)); main_window_str_to_package_list_view_mode(packageListViewMode));
} }
bool showOption; bool showOption;
if (settings.FindBool("show available packages", &showOption) == B_OK) if (settings.FindBool(SETTING_SHOW_AVAILABLE_PACKAGES, &showOption) == B_OK)
fModel.SetShowAvailablePackages(showOption); fModel.SetShowAvailablePackages(showOption);
if (settings.FindBool("show installed packages", &showOption) == B_OK) if (settings.FindBool(SETTING_SHOW_INSTALLED_PACKAGES, &showOption) == B_OK)
fModel.SetShowInstalledPackages(showOption); fModel.SetShowInstalledPackages(showOption);
if (settings.FindBool("show develop packages", &showOption) == B_OK) if (settings.FindBool(SETTING_SHOW_DEVELOP_PACKAGES, &showOption) == B_OK)
fModel.SetShowDevelopPackages(showOption); fModel.SetShowDevelopPackages(showOption);
if (settings.FindBool("show source packages", &showOption) == B_OK) if (settings.FindBool(SETTING_SHOW_SOURCE_PACKAGES, &showOption) == B_OK)
fModel.SetShowSourcePackages(showOption); fModel.SetShowSourcePackages(showOption);
if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
&showOption) == B_OK) {
fModel.SetCanShareAnonymousUsageData(showOption);
}
}
void
MainWindow::_MaybePromptCanShareAnonymousUserData(const BMessage& settings)
{
bool showOption;
if (settings.FindBool(SETTING_CAN_SHARE_ANONYMOUS_USER_DATA,
&showOption) == B_NAME_NOT_FOUND) {
_PromptCanShareAnonymousUserData();
}
}
void
MainWindow::_PromptCanShareAnonymousUserData()
{
BAlert* alert = new(std::nothrow) BAlert(
B_TRANSLATE("Sending anonymous usage data"),
B_TRANSLATE("Would it be acceptable to send anonymous usage data to the"
" HaikuDepotServer system from this computer? You can change your"
" preference in the \"Settings\" window later."),
B_TRANSLATE("No"),
B_TRANSLATE("Yes"));
int32 result = alert->Go();
fModel.SetCanShareAnonymousUsageData(1 == result);
} }
@ -866,6 +916,31 @@ MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package)
} }
void
MainWindow::_IncrementViewCounter(const PackageInfoRef& package)
{
bool shouldIncrementViewCounter = false;
{
AutoLocker<BLocker> modelLocker(fModel.Lock());
bool canShareAnonymousUsageData = fModel.CanShareAnonymousUsageData();
if (canShareAnonymousUsageData && !package->Viewed()) {
package->SetViewed();
shouldIncrementViewCounter = true;
}
}
if (shouldIncrementViewCounter) {
ProcessCoordinator* bulkLoadCoordinator =
ProcessCoordinatorFactory::CreateIncrementViewCounter(
this,
// ProcessCoordinatorListener
&fModel, package);
_AddProcessCoordinator(bulkLoadCoordinator);
}
}
void void
MainWindow::_AdoptPackage(const PackageInfoRef& package) MainWindow::_AdoptPackage(const PackageInfoRef& package)
{ {
@ -1082,6 +1157,14 @@ MainWindow::_PopulatePackageWorker(void* arg)
} }
void
MainWindow::_OpenSettingsWindow()
{
SettingsWindow* window = new SettingsWindow(this, &fModel);
window->Show();
}
void void
MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage) MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
{ {

View File

@ -88,6 +88,10 @@ private:
void _RestoreWindowFrame(const BMessage& settings); void _RestoreWindowFrame(const BMessage& settings);
void _RestoreModelSettings(const BMessage& settings); void _RestoreModelSettings(const BMessage& settings);
void _MaybePromptCanShareAnonymousUserData(
const BMessage& settings);
void _PromptCanShareAnonymousUserData();
void _InitWorkerThreads(); void _InitWorkerThreads();
void _AdoptModelControls(); void _AdoptModelControls();
void _AdoptModel(); void _AdoptModel();
@ -97,6 +101,9 @@ private:
void _AdoptPackage(const PackageInfoRef& package); void _AdoptPackage(const PackageInfoRef& package);
void _ClearPackage(); void _ClearPackage();
void _IncrementViewCounter(
const PackageInfoRef& package);
void _PopulatePackageAsync(bool forcePopulate); void _PopulatePackageAsync(bool forcePopulate);
void _StartBulkLoad(bool force = false); void _StartBulkLoad(bool force = false);
void _BulkLoadCompleteReceived(status_t errorStatus); void _BulkLoadCompleteReceived(status_t errorStatus);
@ -118,6 +125,7 @@ private:
void _OpenLoginWindow( void _OpenLoginWindow(
const BMessage& onSuccessMessage); const BMessage& onSuccessMessage);
void _OpenSettingsWindow();
void _StartUserVerify(); void _StartUserVerify();
void _UpdateAuthorization(); void _UpdateAuthorization();
void _UpdateAvailableRepositories(); void _UpdateAvailableRepositories();

View File

@ -0,0 +1,111 @@
/*
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "SettingsWindow.h"
#include <Button.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <LayoutBuilder.h>
#include <Locker.h>
#include <SeparatorView.h>
#include "Logger.h"
#include "Model.h"
#include "UserUsageConditionsWindow.h"
#include "ServerHelper.h"
#include "WebAppInterface.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SettingsWindow"
#define WINDOW_FRAME BRect(0, 0, 500, 280)
enum {
MSG_APPLY = 'aply',
};
SettingsWindow::SettingsWindow(BWindow* parent, Model* model)
:
BWindow(WINDOW_FRAME, B_TRANSLATE("Settings"),
B_FLOATING_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_CLOSABLE ),
fModel(model)
{
AddToSubset(parent);
_InitUiControls();
_UpdateUiFromModel();
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.AddGroup(B_VERTICAL, 0)
.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
.Add(fCanShareAnonymousUsageDataCheckBox)
.End()
.Add(new BSeparatorView(B_HORIZONTAL))
// rule off
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.SetInsets(0, B_USE_DEFAULT_SPACING,
B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
.AddGlue()
.Add(fCancelButton)
.Add(fApplyButton)
.End();
CenterOnScreen();
}
SettingsWindow::~SettingsWindow()
{
}
void
SettingsWindow::_InitUiControls()
{
fCanShareAnonymousUsageDataCheckBox = new BCheckBox(
"share anonymous usage data",
B_TRANSLATE("Share anonymous usage data with HaikuDepotServer"), NULL);
fApplyButton = new BButton("apply", B_TRANSLATE("Apply"),
new BMessage(MSG_APPLY));
fCancelButton = new BButton("cancel", B_TRANSLATE("Cancel"),
new BMessage(B_QUIT_REQUESTED));
}
void
SettingsWindow::_UpdateUiFromModel()
{
fCanShareAnonymousUsageDataCheckBox->SetValue(
fModel->CanShareAnonymousUsageData() ? 1 : 0);
}
void
SettingsWindow::_UpdateModelFromUi()
{
fModel->SetCanShareAnonymousUsageData(
0 != fCanShareAnonymousUsageDataCheckBox->Value());
}
void
SettingsWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_APPLY:
_UpdateModelFromUi();
BMessenger(this).SendMessage(B_QUIT_REQUESTED);
break;
default:
BWindow::MessageReceived(message);
break;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef SETTINGS_WINDOW_H
#define SETTINGS_WINDOW_H
#include <Locker.h>
#include <Messenger.h>
#include <Window.h>
#include "BarberPole.h"
#include "HaikuDepotConstants.h"
#include "UserDetail.h"
#include "UserUsageConditions.h"
class BButton;
class BCheckBox;
class Model;
class SettingsWindow : public BWindow {
public:
SettingsWindow(BWindow* parent, Model* model);
virtual ~SettingsWindow();
virtual void MessageReceived(BMessage* message);
private:
void _InitUiControls();
void _UpdateUiFromModel();
void _UpdateModelFromUi();
private:
Model* fModel;
BCheckBox* fCanShareAnonymousUsageDataCheckBox;
BButton* fApplyButton;
BButton* fCancelButton;
};
#endif // SETTINGS_WINDOW_H