Audacity 3.2.0
LoginDialog.cpp
Go to the documentation of this file.
1#include "LoginDialog.h"
2
3#include <wx/sizer.h>
4#include <wx/stattext.h>
5#include <wx/button.h>
6#include <wx/textctrl.h>
7#include <wx/hyperlink.h>
8#include <wx/statbmp.h>
9
10#include "Theme.h"
11#include "AllThemeResources.h"
12#include "BasicUI.h"
13#include "ExportUtils.h"
14#include "OAuthService.h"
15#include "widgets/AButton.h"
16
17namespace
18{
19 constexpr auto RestorePasswordURL = "https://audio.com/auth/forgot-password";
20
21 enum
22 {
27 };
28
30 {
31 return mode == LoginDialog::Mode::Create
32 ? XO("Create cloud account")
33 : XO("Sign in to cloud");
34 }
35
36 AButton* MakeLoginButton(wxWindow* parent, wxWindowID id, int imageId, const TranslatableString& label)
37 {
38 const auto button = safenew AButton(parent, id);
39 button->SetButtonType(AButton::FrameTextHButton);
40 button->SetImages(
41 theTheme.Image(bmpHButtonNormal),
42 theTheme.Image(bmpHButtonHover),
43 theTheme.Image(bmpHButtonDown),
44 theTheme.Image(bmpHButtonHover),
45 theTheme.Image(bmpHButtonDisabled));
46 button->SetFrameMid(2);
47 button->SetIcon(theTheme.Image(imageId));
48 button->SetLabel(label);
49 button->SetMinSize({206, 40});
50 button->SetSize(206, 40);
51 button->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
52 return button;
53 }
54
55 wxStaticText* MakeLabel(wxWindow* parent, const wxString& text)
56 {
57 auto label = safenew wxStaticText(parent, wxID_ANY, text);
58 label->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
59 return label;
60 }
61
63 {
64 return [weak = wxWeakRef(dialog), mode](auto code, auto error)
65 {
66 BasicUI::CallAfter([weak, mode, code, error = std::string(error)]
67 {
68 using namespace BasicUI;
69 if (mode == LoginDialog::Mode::Create)
70 {
71 ShowMessageBox(XXO("Oops! It looks like there was an issue with your input.\n"
72 "Please ensure your email is correct and "
73 "that your password is at least 8 characters long"),
74 MessageBoxOptions {}.IconStyle(Icon::Error));
75 }
76 else
77 {
78 ShowMessageBox(XXO("Sorry, but it seems the email or password you entered is incorrect.\n"
79 "Please double-check your credentials and try again!"),
80 MessageBoxOptions {}.IconStyle(Icon::Error));
81 }
82 if(weak)
83 weak->Enable();
84 });
85 };
86 }
87}
88
89BEGIN_EVENT_TABLE(LoginDialog, wxDialogWrapper)
90 EVT_HYPERLINK(ID_SIGNIN, LoginDialog::OnSignIn)
96
97LoginDialog::LoginDialog(wxWindow* parent, wxWindowID id, Mode mode)
98 : wxDialogWrapper(parent, id, DialogNameForMode(mode))
99 , mMode(mode)
100{
101 mOAuthStateSubscription =
103#if defined(__WXMSW__)
104 SetBackgroundColour(theTheme.Colour(clrMedium));
105#endif
106
107 LayoutControls();
108}
109
110bool LoginDialog::SignIn(wxWindow* parent, Mode mode)
111{
112 while(true)
113 {
114 LoginDialog dialog(parent, wxID_ANY, mode);
115 dialog.wxDialogWrapper::Center();
116 auto result = dialog.wxDialogWrapper::ShowModal();
117 if(result == ID_SIGNIN)
118 mode = Mode::SignIn;
119 else if(result == ID_CREATE_ACCOUNT)
120 mode = Mode::Create;
121 else
122 return result == wxID_OK;
123 }
124}
125
127{
128 wxFont titleFont = GetFont();
129 titleFont.SetWeight(wxFONTWEIGHT_BOLD);
130 titleFont.SetPixelSize({ 0, 18 });
131
132 auto topSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
133 wxStaticText* title;
134 topSizer->Add(
135 title = MakeLabel(this,
137 ? _("Create an account to save to the cloud")
138 : _("Sign in to save to the cloud")),
139 0, wxALL, 16);
140 title->SetFont(titleFont);
141 {
142 auto hSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
143 hSizer->Add(MakeLoginButton(this, ID_WITH_GOOGLE, bmpGoogleLogo, XO("Continue with Google")), 1, wxEXPAND);
144 hSizer->AddSpacer(8);
145 hSizer->Add(MakeLoginButton(this, ID_WITH_FACEBOOK, bmpFacebookLogo, XO("Continue with Facebook")), 1, wxEXPAND);
146
147 topSizer->Add(hSizer.release(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 16);
148 }
149
150 {
151 auto vSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
152 vSizer->Add(MakeLabel(this, _("Email")), 0, wxBOTTOM, 5);
153 vSizer->Add(mEmail = safenew wxTextCtrl(this, wxID_ANY), 0, wxEXPAND);
154 topSizer->Add(vSizer.release(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 16);
155 }
156 {
157 auto vSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
158 vSizer->Add(MakeLabel(this, _("Password")), 0, wxBOTTOM, 5);
159 vSizer->Add(mPassword =
160 safenew wxTextCtrl(
161 this,
162 wxID_ANY,
163 wxEmptyString,
164 wxDefaultPosition,
165 wxDefaultSize,
166 wxTE_PASSWORD),
167 0, wxEXPAND);
168 if(mMode == Mode::SignIn)
169 vSizer->Add(safenew wxHyperlinkCtrl(this, wxID_ANY, _("Forgot your password?"), RestorePasswordURL), 0, wxTOP, 10);
170
171 topSizer->Add(vSizer.release(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 16);
172
173 mEmail->Bind(wxEVT_TEXT, &LoginDialog::onUserCredentialsChange, this);
174 mPassword->Bind(wxEVT_TEXT, &LoginDialog::onUserCredentialsChange, this);
175 }
176 if(mMode == Mode::Create)
177 {
178 auto hSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
179 //i18b-hint: followed by hyperlink, keep whitespace at the end
180 hSizer->Add(MakeLabel(this, _("Already have an account? ")), 0, wxALIGN_CENTER_VERTICAL);
181 hSizer->Add(safenew wxHyperlinkCtrl(this, ID_SIGNIN, _("Sign in here"), ""));
182 topSizer->Add(hSizer.release(), 0, wxEXPAND | wxLEFT | wxRIGHT, 16);
183 }
184 else
185 {
186 auto hSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
187 //i18b-hint: followed by hyperlink, keep whitespace at the end
188 hSizer->Add(MakeLabel(this, _("Need an account? ")), 0, wxALIGN_CENTER_VERTICAL);
189 hSizer->Add(safenew wxHyperlinkCtrl(this, ID_CREATE_ACCOUNT, _("Create cloud account"), ""));
190 topSizer->Add(hSizer.release(), 0, wxEXPAND | wxALL, 16);
191 }
192
193 {
194 auto hSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
195 hSizer->Add(safenew wxButton(this, wxID_CANCEL, _("Cancel")));
196 hSizer->AddSpacer(8);
197 hSizer->Add(mContinue = safenew wxButton(this, wxID_OK, _("Continue")));
198 topSizer->Add(hSizer.release(), 0, wxALIGN_RIGHT | wxALL, 16);
199 mContinue->Disable();
200 }
201
202 mEmail->SetFocus();
203
204 SetSizerAndFit(topSizer.release());
205}
206
207void LoginDialog::OnSignIn(wxHyperlinkEvent&)
208{
209 EndModal(ID_SIGNIN);
210}
211
212void LoginDialog::OnCreateAccount(wxHyperlinkEvent&)
213{
214 EndModal(ID_CREATE_ACCOUNT);
215}
216
217void LoginDialog::OnContinue(wxCommandEvent&)
218{
219 if(mMode == Mode::Create)
221 else
223}
224
226{
227 ContinueAuthorize("google");
228}
229
231{
232 ContinueAuthorize("facebook");
233}
234
236{
237 if (mEmail->IsEmpty() || mPassword->IsEmpty())
238 {
239 mContinue->Disable();
240 }
241 else
242 {
243 mContinue->Enable();
244 }
245}
246
248{
249 Disable();
250
251 const auto email = mEmail->GetValue().ToStdString();
252 const auto password = mPassword->GetValue().ToStdString();
253
254 auto& oauthService = audacity::cloud::audiocom::GetOAuthService();
255 oauthService.Register(
256 email,
257 password,
258 [weakThis = wxWeakRef(this)](auto token)
259 {
260 BasicUI::CallAfter([weakThis, token = std::string(token)]()
261 {
262 if(!weakThis)
263 return;
264
265 if(token.empty())
266 {
267 weakThis->Enable();
268 }
269 else
270 weakThis->EndModal(wxID_OK);
271 });
272 },
275}
276
278{
279 Disable();
280
281 const auto email = mEmail->GetValue().ToStdString();
282 const auto password = mPassword->GetValue().ToStdString();
283
284 auto& oauthService = audacity::cloud::audiocom::GetOAuthService();
285 oauthService.Authorize(email, password,
286 [weakThis = wxWeakRef(this)](auto token)
287 {
288 BasicUI::CallAfter([weakThis, token = std::string(token)]()
289 {
290 if(!weakThis)
291 return;
292
293 if(token.empty())
294 {
295 weakThis->Enable();
296 }
297 else
298 weakThis->EndModal(wxID_OK);
299 });
300 },
303}
304
306{
307 if(message.authorised)
308 EndModal(wxOK);
309}
310
311void LoginDialog::ContinueAuthorize(std::string_view authClientId)
312{
315 );
316}
Toolkit-neutral facade for basic user interface services.
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:10
static const auto title
TranslatableString label
Definition: TagsEditor.cpp:165
THEME_API Theme theTheme
Definition: Theme.cpp:82
A wxButton with mouse-over behaviour.
Definition: AButton.h:104
@ FrameTextHButton
Definition: AButton.h:116
wxTextCtrl * mPassword
Definition: LoginDialog.h:47
void OnContinue(wxCommandEvent &)
void LayoutControls()
void OnContinueWithFacebook(wxCommandEvent &)
void OnContinueWithGoogle(wxCommandEvent &)
void onUserCredentialsChange(wxCommandEvent &)
void OnSignIn(wxHyperlinkEvent &)
const Mode mMode
Definition: LoginDialog.h:45
void ContinueCreateAccount()
wxButton * mContinue
Definition: LoginDialog.h:48
void OnOAuthStateChanged(audacity::cloud::audiocom::AuthStateChangedMessage)
void OnCreateAccount(wxHyperlinkEvent &)
static void ContinueAuthorize(std::string_view authClientId)
static bool SignIn(wxWindow *parent, Mode mode=Mode::SignIn)
wxTextCtrl * mEmail
Definition: LoginDialog.h:46
void ContinueSignIn()
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
wxColour & Colour(int iIndex)
wxImage & Image(int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
static std::string MakeOAuthRequestURL(std::string_view authClientId)
Creates a link to authorization request dialog.
bool OpenInDefaultBrowser(const wxString &url)
Open an URL in default browser.
Definition: BasicUI.cpp:246
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:214
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:287
auto DialogNameForMode(LoginDialog::Mode mode)
Definition: LoginDialog.cpp:29
AButton * MakeLoginButton(wxWindow *parent, wxWindowID id, int imageId, const TranslatableString &label)
Definition: LoginDialog.cpp:36
wxStaticText * MakeLabel(wxWindow *parent, const wxString &text)
Definition: LoginDialog.cpp:55
auto DefaultErrorHandler(LoginDialog *dialog, LoginDialog::Mode mode)
Definition: LoginDialog.cpp:62
OAuthService & GetOAuthService()
Returns the instance of the OAuthService.
MessageBoxOptions && IconStyle(Icon style) &&
Definition: BasicUI.h:104
Message that is sent when authorization state changes.
Definition: OAuthService.h:29
bool authorised
Flag that indicates if user is authorised.
Definition: OAuthService.h:36