Vital
Loading...
Searching...
No Matches
authentication_section.cpp
Go to the documentation of this file.
1
3
5
6#include "authentication.h"
7#include "load_save.h"
8#include "fonts.h"
9#include "skin.h"
10
11#if NDEBUG && !NO_AUTH
12
13namespace {
14
15 constexpr int kMsAuthPoll = 1000;
16
17 // Callback called when the token result is retrieved from Firebase.
18 void onTokenResult(const firebase::Future<std::string>& completed_future, void* ref_data) {
19 const MessageManagerLock lock(Thread::getCurrentThread());
20 if (!lock.lockWasGained())
21 return;
22
23 Component::SafePointer<AuthenticationSection>* reference = (Component::SafePointer<AuthenticationSection>*)ref_data;
24
25 if (completed_future.status() != firebase::kFutureStatusComplete) {
26 LoadSave::writeErrorLog("Firebase getting initial token error: not complete");
27 delete reference;
28 return;
29 }
30
31 if (completed_future.error()) {
32 std::string error = "Firebase getting initial token error: error code ";
33 LoadSave::writeErrorLog(error + std::to_string(completed_future.error()));
34 delete reference;
35 return;
36 }
37
38 if (reference->getComponent()) {
39 reference->getComponent()->auth()->setToken(*completed_future.result());
40 reference->getComponent()->notifyLoggedIn();
41 }
42
43 delete reference;
44 }
45
46 // Callback called when the login result is retrieved from Firebase.
47 void onLoginResult(const firebase::Future<firebase::auth::User*>& completed_future, void* ref_data) {
48 const MessageManagerLock lock(Thread::getCurrentThread());
49 if (!lock.lockWasGained())
50 return;
51
52 Component::SafePointer<AuthenticationSection>* reference = (Component::SafePointer<AuthenticationSection>*)ref_data;
53
54 if (completed_future.status() != firebase::kFutureStatusComplete) {
55 LoadSave::writeErrorLog("Firebase login error: not complete");
56 delete reference;
57 return;
58 }
59
60 if (completed_future.error()) {
61 std::string error = "Firebase login error: error code ";
62 LoadSave::writeErrorLog(error + std::to_string(completed_future.error()));
63 delete reference;
64 return;
65 }
66
67 if (reference->getComponent()) {
68 if (completed_future.error())
69 reference->getComponent()->setError(completed_future.error_message());
70 else {
71 firebase::Future<std::string> future = (*completed_future.result())->GetToken(false);
72 Component::SafePointer<AuthenticationSection>* ref =
73 new Component::SafePointer<AuthenticationSection>(reference->getComponent());
74 future.OnCompletion(onTokenResult, ref);
75
77 reference->getComponent()->finishLogin();
78 }
79
80 reference->getComponent()->setButtonSettings(true, "Sign in");
81 }
82
83 delete reference;
84 }
85}
86
87void AuthInitThread::run() {
88 ref_->createAuth();
89}
90
92 body_(Shaders::kRoundedRectangleFragment) {
93 addOpenGlComponent(&body_);
94
95 logo_ = std::make_unique<AppLogo>("logo");
96 addOpenGlComponent(logo_.get());
97
98 sign_in_text_ = std::make_unique<PlainTextComponent>("Sign in", "Sign in");
99 addOpenGlComponent(sign_in_text_.get());
100 sign_in_text_->setFontType(PlainTextComponent::kLight);
101 sign_in_text_->setTextSize(kTextHeight * size_ratio_ * 0.6f);
102 sign_in_text_->setJustification(Justification::centred);
103
104 error_text_ = std::make_unique<PlainTextComponent>("Error", "");
105 addOpenGlComponent(error_text_.get());
106 error_text_->setFontType(PlainTextComponent::kLight);
107 error_text_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
108 error_text_->setJustification(Justification::centredRight);
109
110#if !defined(NO_TEXT_ENTRY)
111 email_ = std::make_unique<OpenGlTextEditor>("Email");
112 email_->addListener(this);
113 addAndMakeVisible(email_.get());
114 addOpenGlComponent(email_->getImageComponent());
115
116 password_ = std::make_unique<OpenGlTextEditor>("Password", 0x2022);
117 password_->addListener(this);
118 addAndMakeVisible(password_.get());
119 addOpenGlComponent(password_->getImageComponent());
120#endif
121
122 sign_in_button_ = std::make_unique<OpenGlToggleButton>("Sign in");
123 sign_in_button_->setText("Sign in");
124 sign_in_button_->setUiButton(true);
125 sign_in_button_->addListener(this);
126 addAndMakeVisible(sign_in_button_.get());
127 addOpenGlComponent(sign_in_button_->getGlComponent());
128
129 forgot_password_ = std::make_unique<ForgotPasswordLink>();
130 addOpenGlComponent(forgot_password_.get());
131 forgot_password_->setFontType(PlainTextComponent::kLight);
132 forgot_password_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
133 forgot_password_->setJustification(Justification::centredLeft);
134
135 work_offline_ = std::make_unique<WorkOffline>();
136 work_offline_->addListener(this);
137 addOpenGlComponent(work_offline_.get());
138 work_offline_->setFontType(PlainTextComponent::kLight);
139 work_offline_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
140 work_offline_->setJustification(Justification::centredRight);
141
142 setWantsKeyboardFocus(true);
143 setSkinOverride(Skin::kOverlay);
144}
145
146AuthenticationSection::~AuthenticationSection() = default;
147
148void AuthenticationSection::init() {
149 if (firebase::App::GetInstance() == nullptr) {
150 startTimer(kMsAuthPoll);
151 return;
152 }
153}
154
157 createAuth();
158 // TODO: Putting this on background thread hangs sometimes.
159 // auth_init_thread_ = std::make_unique<AuthInitThread>(this);
160 // auth_init_thread_->startThread();
161}
162
163void AuthenticationSection::createAuth() {
164 auth_->init();
165 checkAuth();
166}
167
168void AuthenticationSection::checkAuth() {
169 if (!auth_->hasAuth())
170 return;
171
172 firebase::auth::User* user = auth_->auth()->current_user();
173 if (user) {
174 firebase::Future<std::string> future = user->GetToken(true);
175 SafePointer<AuthenticationSection>* self_reference = new SafePointer<AuthenticationSection>(this);
176 future.OnCompletion(onTokenResult, self_reference);
177 }
178
179 const MessageManagerLock lock(Thread::getCurrentThread());
180 if (!lock.lockWasGained())
181 return;
182
183 setVisible(user == nullptr);
184 if (user) {
185 signed_in_email_ = user->email();
187 }
188 else
189 startTimer(kMsAuthPoll);
190}
191
192void AuthenticationSection::timerCallback() {
193 if (!auth_->hasAuth())
194 init();
195 else if (isVisible())
196 checkAuth();
197 else
198 stopTimer();
199}
200
201void AuthenticationSection::mouseUp(const MouseEvent &e) {
202 if (!body_.getBounds().contains(e.getPosition()))
203 setVisible(false);
204}
205
206void AuthenticationSection::resized() {
208
209 Path border;
210
211 int width = kWidth * size_ratio_;
212 int height = kHeight * size_ratio_;
213 int top = kY * size_ratio_;
214 int padding = kPadding * size_ratio_;
215 int logo_width = kImageWidth * size_ratio_;
216 int text_height = kTextHeight * size_ratio_;
217
218 int text_width = width - 2 * padding;
219 int text_x = (getWidth() - text_width) / 2;
220 int error_height = text_height * 0.5;
221 int y = top + height - 2 * padding - 4 * text_height - error_height;
222 if (email_ && password_) {
223 Colour caret = findColour(Skin::kTextEditorCaret, true);
224 Colour body_text = findColour(Skin::kTextEditorCaret, true);
225 Colour selection = findColour(Skin::kTextEditorSelection, true);
226 Colour empty_color = body_text.withMultipliedAlpha(0.5f);
227
228 email_->setTextToShowWhenEmpty(TRANS("Email"), empty_color);
229 password_->setTextToShowWhenEmpty(TRANS("Password"), empty_color);
230
231 email_->setColour(CaretComponent::caretColourId, caret);
232 email_->setColour(TextEditor::textColourId, body_text);
233 email_->setColour(TextEditor::highlightedTextColourId, body_text);
234 email_->setColour(TextEditor::highlightColourId, selection);
235 password_->setColour(CaretComponent::caretColourId, caret);
236 password_->setColour(TextEditor::textColourId, body_text);
237 password_->setColour(TextEditor::highlightedTextColourId, body_text);
238 password_->setColour(TextEditor::highlightColourId, selection);
239
240 email_->setBounds(text_x, y, text_width, text_height);
241 password_->setBounds(text_x, y + 1.25f * text_height, text_width, text_height);
242 }
243
244 int image_x = (getWidth() - logo_width) / 2;
245 int image_y = top + padding;
246 logo_->setBounds(image_x, image_y, logo_width, logo_width);
247
248 Colour text_color = findColour(Skin::kBodyText, true);
249 sign_in_text_->setColor(text_color);
250 sign_in_text_->setBounds(text_x, image_y + logo_width, text_width, text_height);
251 sign_in_text_->setTextSize(kTextHeight * size_ratio_ * 0.6f);
252 sign_in_button_->setBounds(text_x, y + 3 * text_height + error_height + padding, text_width, text_height);
253
254 forgot_password_->setColor(findColour(Skin::kWidgetAccent1, true));
255 forgot_password_->setBounds(password_->getX(), password_->getBottom(), password_->getWidth() / 2, text_height);
256 forgot_password_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
257
258 work_offline_->setColor(findColour(Skin::kWidgetAccent1, true));
259 work_offline_->setBounds(forgot_password_->getRight(), forgot_password_->getY(),
260 password_->getRight() - forgot_password_->getRight(), text_height);
261 work_offline_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
262
263 error_text_->setColor(text_color.interpolatedWith(Colours::red, 0.5f));
264 error_text_->setBounds(password_->getX(), forgot_password_->getBottom(), password_->getWidth(), error_height);
265 error_text_->setTextSize(kTextHeight * size_ratio_ * 0.4f);
266
267 body_.setBounds((getWidth() - width) / 2, top, width, height);
268 body_.setRounding(findValue(Skin::kBodyRounding));
269 body_.setColor(findColour(Skin::kBody, true));
270
271 if (isVisible()) {
272 Image image(Image::ARGB, 1, 1, false);
273 Graphics g(image);
274 paintOpenGlChildrenBackgrounds(g);
275 }
276}
277
278void AuthenticationSection::setVisible(bool should_be_visible) {
279 Overlay::setVisible(should_be_visible);
280
281 if (should_be_visible) {
282 Image image(Image::ARGB, 1, 1, false);
283 Graphics g(image);
284 paintOpenGlChildrenBackgrounds(g);
285 }
286}
287
288void AuthenticationSection::visibilityChanged() {
289 Component::visibilityChanged();
290 if (isShowing() && email_ && email_->isEmpty())
291 email_->grabKeyboardFocus();
292
293 Image image(Image::ARGB, 1, 1, false);
294 Graphics g(image);
295 paintOpenGlChildrenBackgrounds(g);
296}
297
298void AuthenticationSection::workOffline() {
299 setVisible(false);
301}
302
304 auth_->auth()->SignOut();
305 setVisible(true);
306 startTimer(kMsAuthPoll);
307}
308
309void AuthenticationSection::notifyLoggedIn() {
310 for (Listener* listener : listeners_)
311 listener->loggedIn();
312}
313
315 if (isShowing() && email_ && email_->isEmpty())
316 email_->grabKeyboardFocus();
317}
318
319void AuthenticationSection::finishLogin() {
320 setVisible(false);
321 for (Listener* listener : listeners_)
322 listener->loggedIn();
323}
324
325void AuthenticationSection::tryLogin() {
327
328 if (!auth_->hasAuth()) {
329 setVisible(false);
330 return;
331 }
332
333 setError("");
334 setButtonSettings(false, "Signing in...");
335 signed_in_email_ = email_->getText().toStdString();
336 std::string password = password_->getText().toStdString();
337 firebase::Future<firebase::auth::User*> future =
338 auth_->auth()->SignInWithEmailAndPassword(signed_in_email_.c_str(), password.c_str());
339
340 SafePointer<AuthenticationSection>* self_reference = new SafePointer<AuthenticationSection>(this);
341 future.OnCompletion(onLoginResult, self_reference);
342}
343
344#endif
Declares the AuthenticationSection class and related components for user authentication.
A no-op stub implementation used when authentication is disabled.
Definition authentication.h:163
static void create()
No-op create method.
Definition authentication.h:168
AuthenticationSection(Authentication *auth)
Definition authentication_section.h:271
void setFocus()
Definition authentication_section.h:276
void signOut()
Definition authentication_section.h:274
void create()
Definition authentication_section.h:275
static void saveAuthenticated(bool authenticated)
Saves the user's authentication status.
Definition load_save.cpp:1318
static void writeErrorLog(String error_log)
Appends an error message to an error log file.
Definition load_save.cpp:1140
static void saveWorkOffline(bool work_offline)
Saves the user's preference for working offline.
Definition load_save.cpp:1294
A SynthSection that displays an overlay with a background and optional listeners.
Definition overlay.h:180
virtual void resized() override
Called when the overlay is resized. Updates background color and size.
Definition overlay.h:237
void setVisible(bool should_be_visible) override
Sets the visibility of the overlay and notifies listeners.
Definition overlay.h:224
@ kLight
Definition open_gl_image_component.h:309
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kBodyRounding
Definition skin.h:71
@ kWidgetAccent1
Definition skin.h:171
@ kBodyText
Definition skin.h:133
@ kTextEditorSelection
Definition skin.h:203
@ kTextEditorCaret
Definition skin.h:202
@ kBody
Definition skin.h:129
@ kOverlay
Definition skin.h:34