mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
Merge 44f57aa2b9 into 4481c0a7a0
This commit is contained in:
commit
07bc27d2b8
17 changed files with 437 additions and 0 deletions
|
|
@ -34,6 +34,7 @@ set(cockatrice_SOURCES
|
|||
src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp
|
||||
src/interface/widgets/dialogs/dlg_create_game.cpp
|
||||
src/interface/widgets/dialogs/dlg_crash_report.cpp
|
||||
src/interface/widgets/dialogs/dlg_deck_history.cpp
|
||||
src/interface/widgets/dialogs/dlg_default_tags_editor.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_avatar.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_password.cpp
|
||||
|
|
|
|||
176
cockatrice/src/interface/widgets/dialogs/dlg_deck_history.cpp
Normal file
176
cockatrice/src/interface/widgets/dialogs/dlg_deck_history.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#include "dlg_deck_history.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QLocale>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <libcockatrice/deck_list/deck_diff.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_download.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_history_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_history_list.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
QString formatVersionTime(qint64 secsSinceEpoch)
|
||||
{
|
||||
return QLocale().toString(QDateTime::fromSecsSinceEpoch(secsSinceEpoch), QLocale::ShortFormat);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DlgDeckHistory::DlgDeckHistory(int _deckId,
|
||||
const QString &_deckName,
|
||||
int _limit,
|
||||
AbstractClient *_client,
|
||||
QWidget *parent)
|
||||
: QDialog(parent), deckId(_deckId), deckName(_deckName), limit(_limit), client(_client)
|
||||
{
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
|
||||
detailLabel = new QLabel(this);
|
||||
detailLabel->setWordWrap(true);
|
||||
versionsList = new QListWidget(this);
|
||||
previewList = new QListWidget(this);
|
||||
restoreButton = new QPushButton(this);
|
||||
restoreButton->setEnabled(false);
|
||||
|
||||
layout->addWidget(detailLabel);
|
||||
layout->addWidget(versionsList);
|
||||
layout->addWidget(previewList);
|
||||
layout->addWidget(restoreButton);
|
||||
|
||||
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Close, this);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
connect(versionsList, &QListWidget::currentRowChanged, this, &DlgDeckHistory::onSelectionChanged);
|
||||
connect(restoreButton, &QPushButton::clicked, this, &DlgDeckHistory::onRestoreClicked);
|
||||
|
||||
Command_DeckHistoryList listCmd;
|
||||
listCmd.set_deck_id(deckId);
|
||||
listCmd.set_limit(static_cast<google::protobuf::uint32>(limit));
|
||||
PendingCommand *listPend = AbstractClient::prepareSessionCommand(listCmd);
|
||||
connect(listPend, &PendingCommand::finished, this, &DlgDeckHistory::onHistoryFinished);
|
||||
client->sendCommand(listPend);
|
||||
|
||||
Command_DeckDownload downloadCmd;
|
||||
downloadCmd.set_deck_id(deckId);
|
||||
PendingCommand *downloadPend = AbstractClient::prepareSessionCommand(downloadCmd);
|
||||
connect(downloadPend, &PendingCommand::finished, this, &DlgDeckHistory::onCurrentFinished);
|
||||
client->sendCommand(downloadPend);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::retranslateUi()
|
||||
{
|
||||
setWindowTitle(tr("Deck history"));
|
||||
detailLabel->setText(
|
||||
tr("Stored versions of %1 (newest first). Restoring uploads the version as new content.").arg(deckName));
|
||||
restoreButton->setText(tr("Restore selected version"));
|
||||
renderVersions();
|
||||
renderPreview();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::onHistoryFinished(const Response &response, const CommandContainer & /*commandContainer*/)
|
||||
{
|
||||
if (response.response_code() != Response::RespOk) {
|
||||
detailLabel->setText(tr("Could not load version history."));
|
||||
return;
|
||||
}
|
||||
const Response_DeckHistoryList &list = response.GetExtension(Response_DeckHistoryList::ext);
|
||||
versions.clear();
|
||||
for (const DeckVersionInfo &version : list.versions()) {
|
||||
DeckHistoryVersion entry;
|
||||
entry.versionNo = version.version_no();
|
||||
entry.createdAtSecs = static_cast<qint64>(version.created_at());
|
||||
entry.createdByClientId = QString::fromStdString(version.created_by_clientid());
|
||||
entry.hash = QString::fromStdString(version.hash());
|
||||
entry.content = QString::fromStdString(version.content());
|
||||
versions.append(entry);
|
||||
}
|
||||
historyArrived = true;
|
||||
renderVersions();
|
||||
renderPreview();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::onCurrentFinished(const Response &response, const CommandContainer & /*commandContainer*/)
|
||||
{
|
||||
if (response.response_code() != Response::RespOk) {
|
||||
detailLabel->setText(tr("Could not load the current deck."));
|
||||
return;
|
||||
}
|
||||
const Response_DeckDownload &download = response.GetExtension(Response_DeckDownload::ext);
|
||||
currentContent = QString::fromStdString(download.deck());
|
||||
currentArrived = true;
|
||||
renderPreview();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::renderVersions()
|
||||
{
|
||||
const int row = versionsList->currentRow();
|
||||
versionsList->clear();
|
||||
for (const DeckHistoryVersion &version : versions) {
|
||||
QString label = tr("Version %1 — %2").arg(version.versionNo).arg(formatVersionTime(version.createdAtSecs));
|
||||
if (!version.createdByClientId.isEmpty()) {
|
||||
label += tr(" — %1").arg(version.createdByClientId);
|
||||
}
|
||||
versionsList->addItem(label);
|
||||
}
|
||||
if (row >= 0 && row < versionsList->count()) {
|
||||
versionsList->setCurrentRow(row);
|
||||
} else if (versionsList->count() > 0) {
|
||||
versionsList->setCurrentRow(0);
|
||||
}
|
||||
onSelectionChanged();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::renderPreview()
|
||||
{
|
||||
previewList->clear();
|
||||
restoreButton->setEnabled(false);
|
||||
const int row = versionsList->currentRow();
|
||||
if (!historyArrived || !currentArrived || row < 0 || row >= versions.size()) {
|
||||
return;
|
||||
}
|
||||
DeckList currentDeck;
|
||||
DeckList selectedDeck;
|
||||
if (!currentDeck.loadFromString_Native(currentContent) ||
|
||||
!selectedDeck.loadFromString_Native(versions.at(row).content)) {
|
||||
return;
|
||||
}
|
||||
const DeckDiffResult shown = DeckDiff::diff(currentDeck, selectedDeck);
|
||||
for (const DeckCardChange &change : shown.changes) {
|
||||
previewList->addItem(
|
||||
tr("%1: %2 %3 → %4").arg(change.zone).arg(change.cardName).arg(change.oldCount).arg(change.newCount));
|
||||
}
|
||||
restoreButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void DlgDeckHistory::onSelectionChanged()
|
||||
{
|
||||
renderPreview();
|
||||
}
|
||||
|
||||
void DlgDeckHistory::onRestoreClicked()
|
||||
{
|
||||
const int row = versionsList->currentRow();
|
||||
if (row < 0 || row >= versions.size()) {
|
||||
return;
|
||||
}
|
||||
if (QMessageBox::question(this, tr("Restore version"),
|
||||
tr("Restore version %1 as the current deck content? This becomes a new version.")
|
||||
.arg(versions.at(row).versionNo)) != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
emit restoreRequested(deckId, versions.at(row).content);
|
||||
accept();
|
||||
}
|
||||
73
cockatrice/src/interface/widgets/dialogs/dlg_deck_history.h
Normal file
73
cockatrice/src/interface/widgets/dialogs/dlg_deck_history.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file dlg_deck_history.h
|
||||
* @brief Browser for the stored versions of one server deck.
|
||||
*/
|
||||
|
||||
#ifndef DLG_DECK_HISTORY_H
|
||||
#define DLG_DECK_HISTORY_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
class AbstractClient;
|
||||
class CommandContainer;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
class Response;
|
||||
|
||||
/** @brief One stored deck version for display. */
|
||||
struct DeckHistoryVersion
|
||||
{
|
||||
unsigned int versionNo = 0;
|
||||
qint64 createdAtSecs = 0;
|
||||
QString createdByClientId;
|
||||
QString hash;
|
||||
QString content;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class DlgDeckHistory
|
||||
* @brief Lists stored versions with a diff preview against the current deck.
|
||||
*
|
||||
* Restoring uploads the selected version as the new current content through
|
||||
* the regular deck-upload path, so it becomes a version itself instead of
|
||||
* rewriting history. Rejected dialogs restore nothing.
|
||||
*/
|
||||
class DlgDeckHistory : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DlgDeckHistory(int deckId, const QString &deckName, int limit, AbstractClient *client, QWidget *parent = nullptr);
|
||||
void retranslateUi();
|
||||
|
||||
signals:
|
||||
void restoreRequested(int deckId, const QString &content);
|
||||
|
||||
private slots:
|
||||
void onHistoryFinished(const Response &response, const CommandContainer &commandContainer);
|
||||
void onCurrentFinished(const Response &response, const CommandContainer &commandContainer);
|
||||
void onSelectionChanged();
|
||||
void onRestoreClicked();
|
||||
|
||||
private:
|
||||
void renderVersions();
|
||||
void renderPreview();
|
||||
|
||||
int deckId = -1;
|
||||
QString deckName;
|
||||
int limit = 20;
|
||||
AbstractClient *client = nullptr;
|
||||
QList<DeckHistoryVersion> versions;
|
||||
QString currentContent;
|
||||
bool historyArrived = false;
|
||||
bool currentArrived = false;
|
||||
|
||||
QLabel *detailLabel;
|
||||
QListWidget *versionsList;
|
||||
QListWidget *previewList;
|
||||
QPushButton *restoreButton;
|
||||
};
|
||||
|
||||
#endif // DLG_DECK_HISTORY_H
|
||||
|
|
@ -383,12 +383,20 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
connect(&syncIntervalEdit, qOverload<int>(&QSpinBox::valueChanged), &SettingsCache::instance().deckSync(),
|
||||
&DeckSyncSettings::setSyncIntervalMinutes);
|
||||
|
||||
historyLimitEdit.setMinimum(1);
|
||||
historyLimitEdit.setMaximum(100);
|
||||
historyLimitEdit.setValue(settings.deckSync().getHistoryLimit());
|
||||
connect(&historyLimitEdit, qOverload<int>(&QSpinBox::valueChanged), &SettingsCache::instance().deckSync(),
|
||||
&DeckSyncSettings::setHistoryLimit);
|
||||
|
||||
auto *deckSyncGrid = new QGridLayout;
|
||||
deckSyncGrid->addWidget(&conflictDefaultLabel, 0, 0);
|
||||
deckSyncGrid->addWidget(&conflictDefaultSelector, 0, 1);
|
||||
deckSyncGrid->addWidget(&autoSyncCheckBox, 1, 0, 1, 2);
|
||||
deckSyncGrid->addWidget(&syncIntervalLabel, 2, 0);
|
||||
deckSyncGrid->addWidget(&syncIntervalEdit, 2, 1);
|
||||
deckSyncGrid->addWidget(&historyLimitLabel, 3, 0);
|
||||
deckSyncGrid->addWidget(&historyLimitEdit, 3, 1);
|
||||
deckSyncGroupBox = new QGroupBox;
|
||||
deckSyncGroupBox->setLayout(deckSyncGrid);
|
||||
|
||||
|
|
@ -692,5 +700,6 @@ void GeneralSettingsPage::retranslateUi()
|
|||
autoSyncCheckBox.setText(tr("Sync decks automatically"));
|
||||
syncIntervalLabel.setText(tr("Check every:"));
|
||||
syncIntervalEdit.setSuffix(" " + tr("min"));
|
||||
historyLimitLabel.setText(tr("Kept versions per deck:"));
|
||||
resetAllPathsButton->setText(tr("Reset all paths"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ private:
|
|||
QCheckBox autoSyncCheckBox;
|
||||
QLabel syncIntervalLabel;
|
||||
QSpinBox syncIntervalEdit;
|
||||
QLabel historyLimitLabel;
|
||||
QSpinBox historyLimitEdit;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_GENERAL_SETTINGS_PAGE_H
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "../cards/additional_info/deck_color_identity.h"
|
||||
#include "../deck_share/deck_share_utils.h"
|
||||
#include "../deck_share/share_bar_widget.h"
|
||||
#include "../dialogs/dlg_deck_history.h"
|
||||
#include "../dialogs/dlg_sync_conflict.h"
|
||||
#include "../dialogs/dlg_sync_onboarding.h"
|
||||
#include "../interface/widgets/server/remote/remote_decklist_tree_widget.h"
|
||||
|
|
@ -241,6 +242,10 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
|||
aSyncNow->setIcon(qApp->style()->standardIcon(QStyle::SP_BrowserReload));
|
||||
connect(aSyncNow, &QAction::triggered, this, &TabDeckStorage::actSyncNow);
|
||||
|
||||
aDeckHistory = new QAction(this);
|
||||
aDeckHistory->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogDetailedView));
|
||||
connect(aDeckHistory, &QAction::triggered, this, &TabDeckStorage::actDeckHistory);
|
||||
|
||||
// Add actions to toolbars
|
||||
leftToolBar->addAction(aOpenLocalDeck);
|
||||
leftToolBar->addAction(aRenameLocal);
|
||||
|
|
@ -253,6 +258,7 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
|||
rightToolBar->addAction(aOpenRemoteDeck);
|
||||
rightToolBar->addAction(aDownload);
|
||||
rightToolBar->addAction(aSyncNow);
|
||||
rightToolBar->addAction(aDeckHistory);
|
||||
rightToolBar->addAction(aShareDecks);
|
||||
rightToolBar->addAction(aPublishDeck);
|
||||
rightToolBar->addAction(aNewFolder);
|
||||
|
|
@ -314,6 +320,7 @@ void TabDeckStorage::retranslateUi()
|
|||
aPublishDeck->setText(tr("Publish/unpublish deck"));
|
||||
aOpenDecksFolder->setText(tr("Open decks folder"));
|
||||
aSyncNow->setText(tr("Sync now"));
|
||||
aDeckHistory->setText(tr("Version history"));
|
||||
renderSyncStatus();
|
||||
shareBar->retranslateUi();
|
||||
if (shareBar->isVisible()) {
|
||||
|
|
@ -369,6 +376,7 @@ void TabDeckStorage::setRemoteEnabled(bool enabled)
|
|||
aPublishDeck->setEnabled(enabled);
|
||||
aNewFolder->setEnabled(enabled);
|
||||
aDeleteRemoteDeck->setEnabled(enabled);
|
||||
aDeckHistory->setEnabled(enabled);
|
||||
aSyncNow->setEnabled(enabled && !syncManager->isSyncing());
|
||||
|
||||
if (enabled) {
|
||||
|
|
@ -654,6 +662,58 @@ void TabDeckStorage::renderSyncStatus()
|
|||
}
|
||||
}
|
||||
|
||||
void TabDeckStorage::actDeckHistory()
|
||||
{
|
||||
QList<RemoteDeckList_TreeModel::FileNode *> files;
|
||||
for (const auto curRight : serverDirView->getCurrentSelection()) {
|
||||
if (auto *file = dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(curRight)) {
|
||||
files.append(file);
|
||||
}
|
||||
}
|
||||
if (files.size() != 1) {
|
||||
QMessageBox::information(this, tr("Version history"), tr("Select a single server deck to view its history."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto *dialog = new DlgDeckHistory(files.first()->getId(), files.first()->getName(),
|
||||
SettingsCache::instance().deckSync().getHistoryLimit(), client, this);
|
||||
connect(dialog, &DlgDeckHistory::restoreRequested, this, &TabDeckStorage::onHistoryRestoreRequested);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void TabDeckStorage::onHistoryRestoreRequested(int deckId, const QString &content)
|
||||
{
|
||||
DeckList deck;
|
||||
if (!deck.loadFromString_Native(content)) {
|
||||
return;
|
||||
}
|
||||
const QString deckString = deck.writeToString_Native();
|
||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Restored deck is too large"));
|
||||
return;
|
||||
}
|
||||
|
||||
Command_DeckUpload cmd;
|
||||
cmd.set_deck_id(deckId);
|
||||
cmd.set_deck_list(deckString.toStdString());
|
||||
cmd.set_color_identity(getDeckColorIdentity(deck, CardDatabaseManager::query()).toStdString());
|
||||
|
||||
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::onHistoryRestoreFinished);
|
||||
client->sendCommand(pend);
|
||||
}
|
||||
|
||||
void TabDeckStorage::onHistoryRestoreFinished(const Response &response, const CommandContainer & /*commandContainer*/)
|
||||
{
|
||||
if (response.response_code() != Response::RespOk) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to restore deck version"));
|
||||
return;
|
||||
}
|
||||
onSyncStatusMessage(tr("Version restored."));
|
||||
serverDirView->refreshTree();
|
||||
}
|
||||
|
||||
void TabDeckStorage::actRemoteDoubleClick(const QModelIndex &curRight)
|
||||
{
|
||||
if (dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(serverDirView->getNode(curRight))) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ private:
|
|||
QAction *aOpenDecksFolder;
|
||||
QAction *aOpenRemoteDeck, *aDownload, *aShareDecks, *aPublishDeck, *aNewFolder, *aDeleteRemoteDeck;
|
||||
QAction *aSyncNow;
|
||||
QAction *aDeckHistory;
|
||||
QLabel *syncStatusLabel;
|
||||
DeckSyncManager *syncManager;
|
||||
QString syncUsername;
|
||||
|
|
@ -130,6 +131,9 @@ private slots:
|
|||
void deleteDeckFinished(const Response &response, const CommandContainer &commandContainer);
|
||||
|
||||
void actSyncNow();
|
||||
void actDeckHistory();
|
||||
void onHistoryRestoreRequested(int deckId, const QString &content);
|
||||
void onHistoryRestoreFinished(const Response &response, const CommandContainer &commandContainer);
|
||||
void onFirstSyncDetected(int localCount, int serverCount);
|
||||
void onConflictRequest(const DeckSyncConflict &conflict);
|
||||
void onSyncStatusMessage(const QString &message);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ set(PROTO_FILES
|
|||
command_deck_del_dir.proto
|
||||
command_deck_download.proto
|
||||
command_deck_download_public.proto
|
||||
command_deck_history_list.proto
|
||||
command_deck_list.proto
|
||||
command_deck_list_other_user.proto
|
||||
command_deck_new_dir.proto
|
||||
|
|
@ -149,6 +150,7 @@ set(PROTO_FILES
|
|||
response_ban_history.proto
|
||||
response_card_art_rule_entry.proto
|
||||
response_deck_download.proto
|
||||
response_deck_history_list.proto
|
||||
response_deck_list.proto
|
||||
response_deck_share_create.proto
|
||||
response_deck_share_download.proto
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
syntax = "proto2";
|
||||
import "session_commands.proto";
|
||||
|
||||
message Command_DeckHistoryList {
|
||||
extend SessionCommand {
|
||||
optional Command_DeckHistoryList ext = 1035;
|
||||
}
|
||||
optional sint32 deck_id = 1 [default = -1];
|
||||
// Maximum versions to return, newest first. Capped server-side by
|
||||
// deck_sync/max_versions.
|
||||
optional uint32 limit = 2 [default = 20];
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ message Response {
|
|||
DECK_SHARE_DOWNLOAD = 1105; // Response for shared deck download
|
||||
DECK_SHARE_LIST_MINE = 1106; // Response listing the caller's own shares
|
||||
DECK_SYNC_STATUS = 1107; // Response with changed decks since a timestamp
|
||||
DECK_HISTORY_LIST = 1108; // Response listing deck versions
|
||||
CARD_ART_RULE_LIST = 1200; // Response containing a list of card art rules
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
syntax = "proto2";
|
||||
import "response.proto";
|
||||
|
||||
message DeckVersionInfo {
|
||||
optional uint32 version_no = 1;
|
||||
optional uint64 created_at = 2;
|
||||
optional string created_by_clientid = 3;
|
||||
optional string hash = 4;
|
||||
// Full deck content in native format, so the client can diff and
|
||||
// restore without further round trips.
|
||||
optional string content = 5;
|
||||
}
|
||||
|
||||
message Response_DeckHistoryList {
|
||||
extend Response {
|
||||
optional Response_DeckHistoryList ext = 1108;
|
||||
}
|
||||
repeated DeckVersionInfo versions = 1;
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ message SessionCommand {
|
|||
DECK_SHARE_REMOVE = 1033;
|
||||
SUBMIT_PASSWORD_VERIFIER = 1034;
|
||||
DECK_SYNC_CHECK = 1035;
|
||||
DECK_HISTORY_LIST = 1036;
|
||||
REPLAY_LIST = 1100;
|
||||
REPLAY_DOWNLOAD = 1101;
|
||||
REPLAY_MODIFY_MATCH = 1102;
|
||||
|
|
|
|||
|
|
@ -42,3 +42,14 @@ void DeckSyncSettings::setSyncIntervalMinutes(int _syncIntervalMinutes)
|
|||
setValue(_syncIntervalMinutes, "syncIntervalMinutes");
|
||||
emit syncIntervalMinutesChanged(_syncIntervalMinutes);
|
||||
}
|
||||
|
||||
int DeckSyncSettings::getHistoryLimit() const
|
||||
{
|
||||
return qBound(1, getValue("historyLimit", QString(), QString(), 20).toInt(), 100);
|
||||
}
|
||||
|
||||
void DeckSyncSettings::setHistoryLimit(int _historyLimit)
|
||||
{
|
||||
setValue(_historyLimit, "historyLimit");
|
||||
emit historyLimitChanged(_historyLimit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,14 @@ public:
|
|||
void setAutoSync(bool _autoSync);
|
||||
[[nodiscard]] int getSyncIntervalMinutes() const;
|
||||
void setSyncIntervalMinutes(int _syncIntervalMinutes);
|
||||
[[nodiscard]] int getHistoryLimit() const;
|
||||
void setHistoryLimit(int _historyLimit);
|
||||
|
||||
signals:
|
||||
void conflictDefaultChanged(int conflictDefault);
|
||||
void autoSyncChanged(bool autoSync);
|
||||
void syncIntervalMinutesChanged(int syncIntervalMinutes);
|
||||
void historyLimitChanged(int historyLimit);
|
||||
|
||||
private:
|
||||
DeckSyncSettings(const DeckSyncSettings & /*other*/);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
#include <libcockatrice/protocol/pb/command_deck_del_dir.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_download.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_download_public.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_history_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_list_other_user.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_new_dir.pb.h>
|
||||
|
|
@ -130,6 +131,7 @@
|
|||
#include <libcockatrice/protocol/pb/response_card_art_rule_entry.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_clear_blacklisted_banners.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_history_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_share_create.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_share_download.pb.h>
|
||||
|
|
@ -376,6 +378,8 @@ Response::ResponseCode AbstractServerSocketInterface::processExtendedSessionComm
|
|||
return cmdDeckDownload(cmd.GetExtension(Command_DeckDownload::ext), rc);
|
||||
case SessionCommand::DECK_SYNC_CHECK:
|
||||
return cmdDeckSyncCheck(cmd.GetExtension(Command_DeckSyncCheck::ext), rc);
|
||||
case SessionCommand::DECK_HISTORY_LIST:
|
||||
return cmdDeckHistoryList(cmd.GetExtension(Command_DeckHistoryList::ext), rc);
|
||||
case SessionCommand::REPLAY_LIST:
|
||||
return cmdReplayList(cmd.GetExtension(Command_ReplayList::ext), rc);
|
||||
case SessionCommand::REPLAY_DOWNLOAD:
|
||||
|
|
@ -954,6 +958,50 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckSyncCheck(const Com
|
|||
return Response::RespOk;
|
||||
}
|
||||
|
||||
Response::ResponseCode AbstractServerSocketInterface::cmdDeckHistoryList(const Command_DeckHistoryList &cmd,
|
||||
ResponseContainer &rc)
|
||||
{
|
||||
if (authState != PasswordRight) {
|
||||
return Response::RespFunctionNotAllowed;
|
||||
}
|
||||
|
||||
sqlInterface->checkSql();
|
||||
|
||||
QSqlQuery *ownerQuery =
|
||||
sqlInterface->prepareQuery("select 1 from {prefix}_decklist_files where id = :id and id_user = :id_user");
|
||||
ownerQuery->bindValue(":id", cmd.deck_id());
|
||||
ownerQuery->bindValue(":id_user", userInfo->id());
|
||||
if (!sqlInterface->execSqlQuery(ownerQuery)) {
|
||||
return Response::RespContextError;
|
||||
}
|
||||
if (!ownerQuery->next()) {
|
||||
return Response::RespNameNotFound;
|
||||
}
|
||||
|
||||
const int limit = qMin(cmd.has_limit() ? static_cast<int>(cmd.limit()) : 20, servatrice->getDeckSyncMaxVersions());
|
||||
QSqlQuery *query =
|
||||
sqlInterface->prepareQuery("select version_no, unix_timestamp(created_at), created_by_clientid, hash, "
|
||||
"content from {prefix}_deck_versions where deck_id = :deck_id order by version_no "
|
||||
"desc limit :limit");
|
||||
query->bindValue(":deck_id", cmd.deck_id());
|
||||
query->bindValue(":limit", qMax(1, limit));
|
||||
if (!sqlInterface->execSqlQuery(query)) {
|
||||
return Response::RespContextError;
|
||||
}
|
||||
|
||||
Response_DeckHistoryList *re = new Response_DeckHistoryList;
|
||||
while (query->next()) {
|
||||
DeckVersionInfo *version = re->add_versions();
|
||||
version->set_version_no(query->value(0).toUInt());
|
||||
version->set_created_at(query->value(1).toULongLong());
|
||||
version->set_created_by_clientid(query->value(2).toString().toStdString());
|
||||
version->set_hash(query->value(3).toString().toStdString());
|
||||
version->set_content(query->value(4).toString().toStdString());
|
||||
}
|
||||
rc.setResponseExtension(re);
|
||||
return Response::RespOk;
|
||||
}
|
||||
|
||||
Response::ResponseCode AbstractServerSocketInterface::cmdDeckDownloadPublic(const Command_DeckDownloadPublic &cmd,
|
||||
ResponseContainer &rc)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class Command_DeckShareList;
|
|||
class Command_DeckShareListMine;
|
||||
class Command_DeckShareRemove;
|
||||
class Command_DeckShareDownload;
|
||||
class Command_DeckHistoryList;
|
||||
class Command_DeckSyncCheck;
|
||||
class Command_ReplayList;
|
||||
class Command_ReplayDownload;
|
||||
|
|
@ -112,6 +113,7 @@ class Command_ViewLogHistory;
|
|||
class Command_WarnUser;
|
||||
class QObject;
|
||||
class ResponseContainer;
|
||||
class Response_DeckHistoryList;
|
||||
class Response_DeckSyncStatus;
|
||||
|
||||
class AbstractServerSocketInterface : public Server_ProtocolHandler
|
||||
|
|
@ -167,6 +169,7 @@ private:
|
|||
Response::ResponseCode cmdDeckDownload(const Command_DeckDownload &cmd, ResponseContainer &rc);
|
||||
bool syncCheckHelper(int userId, qint64 sinceSecs, Response_DeckSyncStatus *status);
|
||||
Response::ResponseCode cmdDeckSyncCheck(const Command_DeckSyncCheck &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdDeckHistoryList(const Command_DeckHistoryList &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdDeckDownloadPublic(const Command_DeckDownloadPublic &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdDeckShareCreate(const Command_DeckShareCreate &cmd, ResponseContainer &rc);
|
||||
Response::ResponseCode cmdDeckShareList(const Command_DeckShareList &cmd, ResponseContainer &rc);
|
||||
|
|
|
|||
|
|
@ -633,6 +633,18 @@ TEST_F(SettingsDefaultsTest, DeckSync_SyncIntervalMinutes_DefaultAndBounds)
|
|||
ASSERT_EQ(s.getSyncIntervalMinutes(), 60);
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, DeckSync_HistoryLimit_DefaultAndBounds)
|
||||
{
|
||||
DeckSyncSettings s(settingsPath, nullptr);
|
||||
ASSERT_EQ(s.getHistoryLimit(), 20);
|
||||
s.setHistoryLimit(50);
|
||||
ASSERT_EQ(s.getHistoryLimit(), 50);
|
||||
s.setHistoryLimit(0);
|
||||
ASSERT_EQ(s.getHistoryLimit(), 1);
|
||||
s.setHistoryLimit(500);
|
||||
ASSERT_EQ(s.getHistoryLimit(), 100);
|
||||
}
|
||||
|
||||
// --- NetworkSettings ---
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Network_ClientID_Default)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue