-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathsetupwizardcontroller.cpp
More file actions
197 lines (164 loc) · 7.54 KB
/
setupwizardcontroller.cpp
File metadata and controls
197 lines (164 loc) · 7.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include "setupwizardcontroller.h"
#include "gui/application.h"
#include "gui/folderman.h"
#include "pages/accountconfiguredwizardpage.h"
#include "states/abstractsetupwizardstate.h"
#include "states/accountconfiguredsetupwizardstate.h"
#include "states/oauthcredentialssetupwizardstate.h"
#include "states/serverurlsetupwizardstate.h"
#include "states/syncfoldersetupwizardstate.h"
#include "theme.h"
using namespace std::chrono_literals;
namespace {
using namespace OCC;
using namespace OCC::Wizard;
using namespace SetupWizardControllerPrivate;
/**
* Generate list of wizard states to put in the navigation.
* The actual wizard may be in states not within this list to perform tasks in the background without user interaction
* (e.g., to detect the authentication method the server uses).
*/
QList<SetupWizardState> getNavigationEntries()
{
QList<SetupWizardState> states = {
SetupWizardState::ServerUrlState
};
states.append({
SetupWizardState::CredentialsState,
SetupWizardState::AccountConfiguredState,
});
return states;
}
}
namespace OCC::Wizard {
Q_LOGGING_CATEGORY(lcSetupWizardController, "gui.setupwizard.controller")
SetupWizardController::SetupWizardController(SettingsDialog *parent)
: QObject(parent)
, _context(new SetupWizardContext(parent, this))
{
_context->window()->setNavigationEntries(getNavigationEntries());
// we always switch to this state, even if the URL is overridden by the theme
// it will detect
changeStateTo(SetupWizardState::FirstState);
// allow settings dialog to clean up the wizard controller and all the objects it created
connect(_context->window(), &SetupWizardWidget::rejected, this, [this]() {
qCDebug(lcSetupWizardController) << u"wizard window closed";
Q_EMIT finished(nullptr, SyncMode::Invalid);
});
connect(_context->window(), &SetupWizardWidget::navigationEntryClicked, this, [this](SetupWizardState clickedState) {
qCDebug(lcSetupWizardController) << u"pagination entry clicked: current state" << _currentState << u"clicked state" << clickedState;
changeStateTo(clickedState);
});
connect(_context->window(), &SetupWizardWidget::nextButtonClicked, this, [this]() {
qCDebug(lcSetupWizardController) << u"next button clicked, current state" << _currentState;
_currentState->evaluatePage();
});
// in case the back button is clicked, the current page's data is dismissed, and the previous page should be shown
connect(_context->window(), &SetupWizardWidget::backButtonClicked, this, [this]() {
// with enum classes, we have to explicitly cast to a numeric value
const auto currentStateIdx = static_cast<int>(_currentState->state());
Q_ASSERT(currentStateIdx > 0);
qCDebug(lcSetupWizardController) << u"back button clicked, current state" << _currentState;
auto previousState = static_cast<SetupWizardState>(currentStateIdx - 1);
changeStateTo(previousState);
});
}
SetupWizardWidget *SetupWizardController::window()
{
return _context->window();
}
void SetupWizardController::changeStateTo(SetupWizardState nextState, ChangeReason reason)
{
// validate initial state
Q_ASSERT(nextState == SetupWizardState::ServerUrlState || _currentState != nullptr);
if (_currentState != nullptr) {
_currentState->deleteLater();
}
switch (nextState) {
case SetupWizardState::SyncFolderSetupState: {
_currentState = new SyncFolderSetupWizardState(_context);
break;
}
case SetupWizardState::ServerUrlState: {
_currentState = new ServerUrlSetupWizardState(_context);
break;
}
case SetupWizardState::CredentialsState:
_currentState = new OAuthCredentialsSetupWizardState(_context);
break;
case SetupWizardState::AccountConfiguredState: {
_currentState = new AccountConfiguredSetupWizardState(_context);
switch (reason) {
case ChangeReason::Default:
break;
case ChangeReason::EvaluationFailed:
// whenever the evaluation of the last page fails, it's safe to assume it's due to some issue with the advanced
// therefore, we want to show them in that case
auto *page = dynamic_cast<AccountConfiguredWizardPage *>(_currentState->page());
if (OC_ENSURE(page != nullptr)) {
page->setShowAdvancedSettings(true);
}
}
break;
}
default:
Q_UNREACHABLE();
}
Q_ASSERT(_currentState != nullptr);
Q_ASSERT(_currentState->state() == nextState);
qCDebug(lcSetupWizardController) << u"Current wizard state:" << _currentState->state();
connect(_currentState, &AbstractSetupWizardState::evaluationSuccessful, this, [this]() {
switch (_currentState->state()) {
case SetupWizardState::SyncFolderSetupState: {
changeStateTo(SetupWizardState::ServerUrlState);
return;
}
case SetupWizardState::ServerUrlState: {
changeStateTo(SetupWizardState::CredentialsState);
return;
}
case SetupWizardState::CredentialsState: {
// for now, we assume there is only a single instance
const auto webFingerInstances = _context->accountBuilder().webFingerInstances();
if (!webFingerInstances.isEmpty()) {
Q_ASSERT(webFingerInstances.size() == 1);
_context->accountBuilder().setWebFingerSelectedInstance(webFingerInstances.front());
}
// not a fan of performing this job here, should be moved into its own (headless) state IMO
// we can bind it to the current state, which will be cleaned up by changeStateTo(...) as soon as the job finished
auto fetchUserInfoJob = _context->startFetchUserInfoJob(_currentState);
connect(fetchUserInfoJob, &CoreJob::finished, this, [this, fetchUserInfoJob] {
if (fetchUserInfoJob->success()) {
auto result = fetchUserInfoJob->result().value<FetchUserInfoResult>();
_context->accountBuilder().setDisplayName(result.displayName());
changeStateTo(SetupWizardState::AccountConfiguredState);
} else if (fetchUserInfoJob->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 401) {
_context->window()->showErrorMessage(tr("Invalid credentials"));
changeStateTo(_currentState->state());
} else {
_context->window()->showErrorMessage(tr("Failed to retrieve user information from server"));
changeStateTo(_currentState->state());
}
});
return;
}
case SetupWizardState::AccountConfiguredState: {
const auto *pagePtr = qobject_cast<AccountConfiguredWizardPage *>(_currentState->page());
auto account = _context->accountBuilder().build();
Q_ASSERT(account != nullptr);
Q_EMIT finished(account, pagePtr->syncMode());
return;
}
default:
Q_UNREACHABLE();
}
});
connect(_currentState, &AbstractSetupWizardState::evaluationFailed, this, [this](const QString &errorMessage) {
_currentState->deleteLater();
_context->window()->showErrorMessage(errorMessage);
changeStateTo(_currentState->state(), ChangeReason::EvaluationFailed);
});
_context->window()->displayPage(_currentState->page(), _currentState->state());
}
SetupWizardController::~SetupWizardController() noexcept { }
}