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.
*/
#ifndef HAIKU_DEPOT_CONSTANTS_H
@ -73,6 +73,15 @@ enum BitmapSize {
#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'
enum {
RSRC_STAR_BLUE = 510,

View File

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

View File

@ -212,7 +212,8 @@ Model::Model()
fShowAvailablePackages(true),
fShowInstalledPackages(true),
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
Model::SetShowAvailablePackages(bool show)
{

View File

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

View File

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

View File

@ -253,7 +253,8 @@ public:
{ return fName; }
void SetTitle(const BString& title);
const BString& Title() const;
const BPackageVersion& Version() const
const BPackageVersion&
Version() const
{ return fVersion; }
void SetShortDescription(const BString& description);
const BString& ShortDescription() const
@ -336,6 +337,10 @@ public:
int64 Size() const
{ return fSize; }
void SetViewed();
bool Viewed() const
{ return fViewed; }
void SetDepotName(const BString& depotName);
const BString& DepotName() const
{ return fDepotName; }
@ -387,6 +392,7 @@ private:
BString fFileName;
int64 fSize;
BString fDepotName;
bool fViewed;
bool fIsCollatingChanges;
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.
*/
@ -14,6 +14,7 @@
#include "AbstractServerProcess.h"
#include "HaikuDepotConstants.h"
#include "IncrementViewCounterProcess.h"
#include "LocalPkgDataLoadProcess.h"
#include "LocalRepositoryUpdateProcess.h"
#include "Logger.h"
@ -34,6 +35,21 @@
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*
ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
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.
*/
@ -9,6 +9,8 @@
#include <SupportDefs.h>
#include "PackageInfo.h"
class Model;
class PackageInfoListener;
class ProcessCoordinator;
@ -21,6 +23,11 @@ class UserDetailVerifierListener;
class ProcessCoordinatorFactory {
public:
static ProcessCoordinator* CreateIncrementViewCounter(
ProcessCoordinatorListener*
processCoordinatorListener,
Model* model, const PackageInfoRef package);
static ProcessCoordinator* CreateBulkLoadCoordinator(
PackageInfoListener *packageInfoListener,
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 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.
*/
@ -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
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

View File

@ -1,6 +1,6 @@
/*
* 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.
*/
#ifndef WEB_APP_INTERFACE_H
@ -12,6 +12,7 @@
#include <String.h>
#include <package/PackageVersion.h>
#include "PackageInfo.h"
#include "UserCredentials.h"
#include "UserDetail.h"
#include "UserUsageConditions.h"
@ -120,6 +121,11 @@ public:
const BString& passwordClear,
BMessage& message);
status_t IncrementViewCounter(
const PackageInfoRef package,
const DepotInfoRef depot,
BMessage& message);
static int32 ErrorCodeFromResponse(
BMessage& responseEnvelopeMessage);

View File

@ -47,6 +47,7 @@
#include "RatePackageWindow.h"
#include "support.h"
#include "ScreenshotWindow.h"
#include "SettingsWindow.h"
#include "ToLatestUserUsageConditionsWindow.h"
#include "UserLoginWindow.h"
#include "UserUsageConditionsWindow.h"
@ -61,6 +62,7 @@ enum {
MSG_REFRESH_REPOS = 'mrrp',
MSG_MANAGE_REPOS = 'mmrp',
MSG_SOFTWARE_UPDATER = 'mswu',
MSG_SETTINGS = 'stgs',
MSG_LOG_IN = 'lgin',
MSG_AUTHORIZATION_CHANGED = 'athc',
MSG_CATEGORIES_LIST_CHANGED = 'clic',
@ -76,7 +78,6 @@ enum {
};
#define KEY_ERROR_STATUS "errorStatus"
#define KEY_PACKAGE_LIST_VIEW_MODE "packageListViewMode"
#define TAB_PROMINENT_PACKAGES 0
#define TAB_ALL_PACKAGES 1
@ -195,6 +196,7 @@ MainWindow::MainWindow(const BMessage& settings)
fPackageListView->LoadState(&columnSettings);
_RestoreModelSettings(settings);
_MaybePromptCanShareAnonymousUserData(settings);
if (fModel.PackageListViewMode() == PROMINENT)
fListTabs->Select(TAB_PROMINENT_PACKAGES);
@ -343,6 +345,10 @@ MainWindow::MessageReceived(BMessage* message)
_OpenLoginWindow(BMessage());
break;
case MSG_SETTINGS:
_OpenSettingsWindow();
break;
case MSG_LOG_OUT:
fModel.SetNickname("");
break;
@ -431,8 +437,10 @@ MainWindow::MessageReceived(BMessage* message)
}
if (!package.IsSet() || name != package->Name())
debugger("unable to find the named package");
else
else {
_AdoptPackage(package);
_IncrementViewCounter(package);
}
} else {
_ClearPackage();
}
@ -577,15 +585,19 @@ MainWindow::StoreSettings(BMessage& settings) const
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(
fModel.PackageListViewMode()));
settings.AddBool("show available packages",
settings.AddBool(SETTING_SHOW_AVAILABLE_PACKAGES,
fModel.ShowAvailablePackages());
settings.AddBool("show installed packages",
settings.AddBool(SETTING_SHOW_INSTALLED_PACKAGES,
fModel.ShowInstalledPackages());
settings.AddBool("show develop packages", fModel.ShowDevelopPackages());
settings.AddBool("show source packages", fModel.ShowSourcePackages());
settings.AddBool(SETTING_SHOW_DEVELOP_PACKAGES,
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());
@ -627,6 +639,14 @@ MainWindow::GetModel()
void
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"));
fRefreshRepositoriesItem = new BMenuItem(
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)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Check for updates"
B_UTF8_ELLIPSIS), new BMessage(MSG_SOFTWARE_UPDATER)));
menuBar->AddItem(menu);
fRepositoryMenu = new BMenu(B_TRANSLATE("Repositories"));
@ -756,21 +775,52 @@ void
MainWindow::_RestoreModelSettings(const BMessage& settings)
{
BString packageListViewMode;
if (settings.FindString(KEY_PACKAGE_LIST_VIEW_MODE,
if (settings.FindString(SETTING_PACKAGE_LIST_VIEW_MODE,
&packageListViewMode) == B_OK) {
fModel.SetPackageListViewMode(
main_window_str_to_package_list_view_mode(packageListViewMode));
}
bool showOption;
if (settings.FindBool("show available packages", &showOption) == B_OK)
if (settings.FindBool(SETTING_SHOW_AVAILABLE_PACKAGES, &showOption) == B_OK)
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);
if (settings.FindBool("show develop packages", &showOption) == B_OK)
if (settings.FindBool(SETTING_SHOW_DEVELOP_PACKAGES, &showOption) == B_OK)
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);
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
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
MainWindow::_OpenLoginWindow(const BMessage& onSuccessMessage)
{

View File

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