blob: 79f4708b5a1612dc6814d229aa5416ff1c403db1 [file] [log] [blame]
Loïc Siretfcb4ca62016-09-21 17:12:09 -04001/*
2 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
3 * Author: Loïc Siret <loic.siret@savoirfairelinux.com>
Kateryna Kostiukecaa3952018-07-13 16:00:34 -04004 * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
Loïc Siretfcb4ca62016-09-21 17:12:09 -04005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#import "RingWizardNewAccountVC.h"
22
23
24//Cocoa
Loïc Siretfcb4ca62016-09-21 17:12:09 -040025#import <Quartz/Quartz.h>
Kateryna Kostiuk91b44e32018-09-28 17:08:02 -040026#import <AVFoundation/AVFoundation.h>
Loïc Siretfcb4ca62016-09-21 17:12:09 -040027
28//Qt
29#import <QUrl>
30#import <QPixmap>
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040031#import <QSize>
32#import <QtMacExtras/qmacfunctions.h>
Loïc Siretfcb4ca62016-09-21 17:12:09 -040033
34//LRC
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040035#import <api/lrc.h>
36#import <api/newaccountmodel.h>
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -040037#import <api/account.h>
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040038#import <interfaces/pixmapmanipulatori.h>
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -040039#import <namedirectory.h>
Loïc Siretfcb4ca62016-09-21 17:12:09 -040040
Loïc Siretfcb4ca62016-09-21 17:12:09 -040041#import "Constants.h"
42#import "views/NSImage+Extensions.h"
43#import "views/NSColor+RingTheme.h"
Andreas Traczyk92c101e2018-07-03 14:43:53 -040044#import "utils.h"
Loïc Siretfcb4ca62016-09-21 17:12:09 -040045
46@interface RingWizardNewAccountVC ()
47@end
48
49@implementation RingWizardNewAccountVC
50{
Loïc Siret3652cfb2016-10-27 10:12:07 -040051 __unsafe_unretained IBOutlet NSView* loadingView;
52 __unsafe_unretained IBOutlet NSView* creationView;
53
Loïc Siretfcb4ca62016-09-21 17:12:09 -040054 __unsafe_unretained IBOutlet NSButton* photoView;
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -040055 __unsafe_unretained IBOutlet NSButton* registerInfoButton;
56 __unsafe_unretained IBOutlet NSButton* enableUsername;
Alexandre Lision882289b2016-10-31 16:10:39 -040057 __unsafe_unretained IBOutlet NSTextField* displayNameField;
58 __unsafe_unretained IBOutlet NSTextField* registeredNameField;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -040059 __unsafe_unretained IBOutlet NSTextField* registeredNameError;
60 __unsafe_unretained IBOutlet NSTextField* passwordError;
Loïc Siretfcb4ca62016-09-21 17:12:09 -040061 __unsafe_unretained IBOutlet NSSecureTextField* passwordField;
Loïc Siret3652cfb2016-10-27 10:12:07 -040062 __unsafe_unretained IBOutlet NSSecureTextField* passwordRepeatField;
Kateryna Kostiuk87ae2bf2018-05-04 13:46:17 -040063 __unsafe_unretained IBOutlet NSImageView* addProfilePhotoImage;
Loïc Siret3652cfb2016-10-27 10:12:07 -040064
65 __unsafe_unretained IBOutlet NSProgressIndicator* progressBar;
Alexandre Lision882289b2016-10-31 16:10:39 -040066
Alexandre Lision882289b2016-10-31 16:10:39 -040067 __unsafe_unretained IBOutlet NSProgressIndicator* indicatorLookupResult;
68
69 __unsafe_unretained IBOutlet NSPopover* helpBlockchainContainer;
70 __unsafe_unretained IBOutlet NSPopover* helpPasswordContainer;
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -050071 __unsafe_unretained IBOutlet NSLayoutConstraint* buttonTopConstraint;
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -050072 __unsafe_unretained IBOutlet NSButton* passwordButton;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -040073 __unsafe_unretained IBOutlet NSStackView* repeatPasswordView;
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -040074 __unsafe_unretained IBOutlet NSStackView* passwordButtonContainer;
Alexandre Lision882289b2016-10-31 16:10:39 -040075
Alexandre Lision882289b2016-10-31 16:10:39 -040076 QMetaObject::Connection registeredNameFound;
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040077 QMetaObject::Connection accountCreated;
78 QMetaObject::Connection accountRemoved;
Alexandre Lision882289b2016-10-31 16:10:39 -040079
80 BOOL lookupQueued;
81 NSString* usernameWaitingForLookupResult;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040082 QString accountToCreate;
Loïc Siretfcb4ca62016-09-21 17:12:09 -040083}
84
Alexandre Lision882289b2016-10-31 16:10:39 -040085NSInteger const DISPLAY_NAME_TAG = 1;
86NSInteger const BLOCKCHAIN_NAME_TAG = 2;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -040087NSInteger const PASSWORD_TAG = 3;
88NSInteger const REPEAT_PASSWORD_TAG = 4;
Loïc Siretfcb4ca62016-09-21 17:12:09 -040089
Loïc Siret3652cfb2016-10-27 10:12:07 -040090//ERROR CODE for textfields validations
91NSInteger const ERROR_PASSWORD_TOO_SHORT = -1;
92NSInteger const ERROR_REPEAT_MISMATCH = -2;
93
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -040094BOOL isRendevous = false;
95
Kateryna Kostiukecaa3952018-07-13 16:00:34 -040096@synthesize accountModel;
97
98-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(lrc::api::NewAccountModel*) accountModel {
99 if (self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
100 {
101 self.accountModel = accountModel;
102 }
103 return self;
104}
105
Loïc Siret3652cfb2016-10-27 10:12:07 -0400106- (BOOL)produceError:(NSError**)error withCode:(NSInteger)code andMessage:(NSString*)message
107{
108 if (error != NULL){
109 NSDictionary *errorDetail = @{NSLocalizedDescriptionKey: message};
110 *error = [NSError errorWithDomain:@"Input" code:code userInfo:errorDetail];
111 }
112 return NO;
113}
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400114
Alexandre Lision882289b2016-10-31 16:10:39 -0400115- (IBAction)showBlockchainHelp:(id)sender
116{
117 [helpBlockchainContainer showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
118}
119
120- (IBAction)showPasswordHelp:(id)sender
121{
122 [helpPasswordContainer showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
123}
124
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400125- (void)prepareViewToShow:(BOOL)isRendevousAccount {
126 isRendevous = isRendevousAccount;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400127 [self.view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
128 [creationView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiuk61d41162019-10-25 16:51:44 -0400129 [loadingView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400130 [passwordField setHidden: YES];
131 [repeatPasswordView setHidden: YES];
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400132 buttonTopConstraint.constant = isRendevous ? 15 : 25;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400133}
134
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400135- (void)show {
136 NSString *buttonTitle = isRendevous ?
Kateryna Kostiuk63d766d2020-10-02 14:20:28 -0400137 NSLocalizedString(@"Choose a name for your rendezvous point", @"Choose registered name for rendezvous") :
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400138 NSLocalizedString(@"Choose a username for your account", @"Choose registered name for account");
139 [enableUsername setTitle:buttonTitle];
140 [passwordButtonContainer setHidden: isRendevous];
141 [registerInfoButton setHidden: isRendevous];
Alexandre Lision882289b2016-10-31 16:10:39 -0400142 [displayNameField setTag:DISPLAY_NAME_TAG];
143 [registeredNameField setTag:BLOCKCHAIN_NAME_TAG];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400144 [photoView setWantsLayer: YES];
145 photoView.layer.cornerRadius = photoView.frame.size.width / 2;
146 photoView.layer.masksToBounds = YES;
Alexandre Lisionc2ad6392016-11-08 11:20:34 -0500147 self.signUpBlockchainState = YES;
148 [self toggleSignupRing:nil];
Kateryna Kostiuk87ae2bf2018-05-04 13:46:17 -0400149 [addProfilePhotoImage setWantsLayer: YES];
150 [photoView setBordered:YES];
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500151 [passwordButton setState: NSControlStateValueOff];
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500152 self.registeredName = @"";
153 self.password = @"";
154 self.repeatPassword = @"";
Loïc Siret3652cfb2016-10-27 10:12:07 -0400155 [self display:creationView];
156}
157
Loïc Siret3652cfb2016-10-27 10:12:07 -0400158- (void)display:(NSView *)view
159{
160 [self.delegate showView:view];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400161}
162
163- (IBAction)editPhoto:(id)sender
164{
Loïc Siret3652cfb2016-10-27 10:12:07 -0400165 auto pictureTaker = [IKPictureTaker pictureTaker];
Kateryna Kostiukdc563242019-08-19 12:05:54 -0400166#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
Kateryna Kostiuk91b44e32018-09-28 17:08:02 -0400167 if (@available(macOS 10.14, *)) {
168 AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
169 if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied)
170 {
171 [pictureTaker setValue:0 forKey:IKPictureTakerAllowsVideoCaptureKey];
172 }
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400173
Kateryna Kostiuk91b44e32018-09-28 17:08:02 -0400174 if(authStatus == AVAuthorizationStatusNotDetermined)
175 {
176 [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
177 if(!granted){
178 [pictureTaker setValue:0 forKey:IKPictureTakerAllowsVideoCaptureKey];
179 }
180 }];
181 }
182 }
Kateryna Kostiukdc563242019-08-19 12:05:54 -0400183#endif
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400184 [pictureTaker beginPictureTakerSheetForWindow:[self.delegate window]
185 withDelegate:self
186 didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:)
187 contextInfo:nil];
188
189}
190
191- (void)pictureTakerDidEnd:(IKPictureTaker *) picker
Alexandre Lision882289b2016-10-31 16:10:39 -0400192 returnCode:(NSInteger) code
193 contextInfo:(void*) contextInfo
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400194{
Kateryna Kostiuk256814e2018-09-04 14:47:33 -0400195 //do nothing when editing canceled
196 if (code == 0) {
197 return;
198 }
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400199 if (auto outputImage = [picker outputImage]) {
Kateryna Kostiuk87ae2bf2018-05-04 13:46:17 -0400200 [photoView setBordered:NO];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400201 auto image = [picker inputImage];
Kateryna Kostiuk2f2ef952019-05-07 11:04:41 -0400202 CGFloat newSize = MIN(MIN(image.size.height, image.size.width), MAX_IMAGE_SIZE);
203 outputImage = [outputImage imageResizeInsideMax: newSize];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400204 [photoView setImage:outputImage];
Kateryna Kostiuk87ae2bf2018-05-04 13:46:17 -0400205 [addProfilePhotoImage setHidden:YES];
206 } else if(!photoView.image) {
207 [photoView setBordered:YES];
208 [addProfilePhotoImage setHidden:NO];
Alexandre Lisionc2ad6392016-11-08 11:20:34 -0500209 }
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400210}
211
Loïc Siret3652cfb2016-10-27 10:12:07 -0400212#pragma mark - Input validation
Alexandre Lision882289b2016-10-31 16:10:39 -0400213
Loïc Siret3652cfb2016-10-27 10:12:07 -0400214- (BOOL)isPasswordValid
215{
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400216 return self.password.length >= 6 || self.password.length == 0;
Loïc Siret3652cfb2016-10-27 10:12:07 -0400217}
218
219- (BOOL)isRepeatPasswordValid
220{
Anthony Léonard24110e82017-09-15 16:29:11 -0400221 return [self.password isEqualToString:self.repeatPassword] || ([self.password length] == 0 && [self.repeatPassword length] == 0);
Loïc Siret3652cfb2016-10-27 10:12:07 -0400222}
223
224- (BOOL)validateRepeatPassword:(NSError **)error
225{
226 if (!self.isRepeatPasswordValid){
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400227 passwordError.stringValue = NSLocalizedString(@"Passwords don't match",
228 @"Indication for user");
Loïc Siret3652cfb2016-10-27 10:12:07 -0400229 return [self produceError:error
230 withCode:ERROR_REPEAT_MISMATCH
231 andMessage:NSLocalizedString(@"Passwords don't match",
Alexandre Lision882289b2016-10-31 16:10:39 -0400232 @"Indication for user")];
Loïc Siret3652cfb2016-10-27 10:12:07 -0400233 }
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400234 passwordError.stringValue = @"";
Loïc Siret3652cfb2016-10-27 10:12:07 -0400235 return YES;
236}
237
238- (BOOL)validatePassword:(NSError **)error
239{
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400240 if (!self.isPasswordValid){
241 passwordError.stringValue = NSLocalizedString(@"Password is too short",
242 @"Indication for user");
Loïc Siret3652cfb2016-10-27 10:12:07 -0400243 return [self produceError:error
244 withCode:ERROR_PASSWORD_TOO_SHORT
245 andMessage:NSLocalizedString(@"Password is too short",
Alexandre Lision882289b2016-10-31 16:10:39 -0400246 @"Indication for user")];
Loïc Siret3652cfb2016-10-27 10:12:07 -0400247 }
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400248 passwordError.stringValue = @"";
Loïc Siret3652cfb2016-10-27 10:12:07 -0400249 return YES;
250}
251
252- (BOOL)validateUserInputPassword:(NSError **)error
253{
254 return [self validatePassword:error] && [self validateRepeatPassword:error];
255}
256
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400257- (IBAction)createRingAccount:(id)sender
258{
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400259 QObject::disconnect(accountCreated);
260 QObject::disconnect(accountRemoved);
261 accountCreated = QObject::connect(self.accountModel,
262 &lrc::api::NewAccountModel::accountAdded,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400263 [self] (const QString& accountID) {
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400264 if(accountID.compare(accountToCreate) != 0) {
265 return;
266 }
267 QObject::disconnect(accountCreated);
268 QObject::disconnect(accountRemoved);
269 //set account avatar
270 if([photoView image]) {
271 NSImage *avatarImage = [photoView image];
Kateryna Kostiuk14b8aa72020-11-11 10:40:15 -0500272 NSData* imageData = [avatarImage TIFFRepresentation];
273 NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData: imageData];
274 NSDictionary *properties = [[NSDictionary alloc] init];
275 imageData = [imageRep representationUsingType:NSPNGFileType properties: properties];
276 NSString * dataString = [imageData base64EncodedStringWithOptions:0];
277 self.accountModel->setAvatar(accountID, QString::fromNSString(dataString));
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400278 }
279 //register username
280 if (self.registeredName && ![self.registeredName isEqualToString:@""]) {
281 NSString *passwordString = self.password ? self.password: @"";
282 NSString *usernameString = self.registeredName;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400283 self.accountModel->registerName(accountID,
284 QString::fromNSString(passwordString),
285 QString::fromNSString(usernameString));
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400286 }
Kateryna Kostiuk0c0801e2019-07-18 20:10:51 -0400287 lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(accountID);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400288 accountProperties.Ringtone.ringtonePath = QString::fromNSString(defaultRingtonePath());
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400289 accountProperties.isRendezVous = isRendevous;
Kateryna Kostiuk0c0801e2019-07-18 20:10:51 -0400290 self.accountModel->setAccountConfig(accountID, accountProperties);
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400291 [self registerDefaultPreferences];
Kateryna Kostiuk61d41162019-10-25 16:51:44 -0400292 [self.delegate didCreateAccountWithSuccess:YES accountId: accountToCreate];
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400293 });
294 //if account creation failed remove loading view
295 accountRemoved = QObject::connect(self.accountModel,
296 &lrc::api::NewAccountModel::accountRemoved,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400297 [self] (const QString& accountID) {
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400298 if(accountID.compare(accountToCreate) != 0) {
299 return;
300 }
301 QObject::disconnect(accountCreated);
302 QObject::disconnect(accountRemoved);
Kateryna Kostiuk61d41162019-10-25 16:51:44 -0400303 [self.delegate didCreateAccountWithSuccess:NO accountId: accountToCreate];
Kateryna Kostiukecaa3952018-07-13 16:00:34 -0400304 });
Loïc Siret3652cfb2016-10-27 10:12:07 -0400305 [self display:loadingView];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400306 [progressBar startAnimation:nil];
Loïc Siret3652cfb2016-10-27 10:12:07 -0400307
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400308 accountToCreate = self.accountModel->createNewAccount(lrc::api::profile::Type::RING, QString::fromNSString(displayNameField.stringValue),"",QString::fromNSString(passwordField.stringValue), "");
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400309}
310
311/**
312 * Set default values for preferences
313 */
314- (void)registerDefaultPreferences
315{
Andreas Traczyk92c101e2018-07-03 14:43:53 -0400316 if (!appSandboxed()) {
317 // enable AutoStartup
318 LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
319 if (loginItemsRef == nil) return;
320 CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
321 LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
322 if (itemRef) CFRelease(itemRef);
323 }
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400324
325 // enable Notifications
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500326 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:Preferences::CallNotifications];
327 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:Preferences::MessagesNotifications];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400328}
329
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400330- (IBAction)cancel:(id)sender
331{
Kateryna Kostiuk61d41162019-10-25 16:51:44 -0400332 [self.delegate didCreateAccountWithSuccess:NO accountId: accountToCreate];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400333}
334
Alexandre Lision882289b2016-10-31 16:10:39 -0400335#pragma mark - UserNameRegistration delegate methods
336
337- (IBAction)toggleSignupRing:(id)sender
338{
339 if (self.withBlockchain) {
340 [self lookupUserName];
341 }
342}
343
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500344- (IBAction)togglePasswordButton:(NSButton *)sender
345{
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400346 [passwordField setHidden: !passwordField.hidden];
347 [repeatPasswordView setHidden: !repeatPasswordView.hidden];
Kateryna Kostiuk707c7ac2020-09-18 11:27:13 -0400348 buttonTopConstraint.constant = repeatPasswordView.hidden ? 25 : 15;
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400349 [self display:creationView];
Kateryna Kostiuk23222fe2018-11-16 14:28:02 -0500350}
351
Alexandre Lision882289b2016-10-31 16:10:39 -0400352- (BOOL)withBlockchain
353{
354 return self.signUpBlockchainState == NSOnState;
355}
356
357- (BOOL)userNameAvailableORNotBlockchain
358{
359 return !self.withBlockchain || (self.registeredName.length > 0 && self.isUserNameAvailable);
360}
361
362- (void)showLookUpAvailable:(BOOL)available andText:(NSString *)message
363{
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400364 if (registeredNameField.stringValue.length > 0) {
365 registeredNameError.stringValue = message;
366 }
367 [indicatorLookupResult setHidden:YES];
368 [indicatorLookupResult stopAnimation:nil];
Alexandre Lision882289b2016-10-31 16:10:39 -0400369}
370
371- (void)onUsernameAvailabilityChangedWithNewAvailability:(BOOL)newAvailability
372{
373 self.isUserNameAvailable = newAvailability;
374}
375
376- (void)hideLookupSpinner
377{
378 [indicatorLookupResult setHidden:YES];
379}
380
381- (void)showLookupSpinner
382{
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400383 registeredNameError.stringValue = @"";
384 if (registeredNameField.stringValue.length > 0) {
385 [indicatorLookupResult setHidden:NO];
386 [indicatorLookupResult startAnimation:nil];
387 }
Alexandre Lision882289b2016-10-31 16:10:39 -0400388}
389
390- (BOOL)lookupUserName
391{
392 [self showLookupSpinner];
393 QObject::disconnect(registeredNameFound);
394 registeredNameFound = QObject::connect(
395 &NameDirectory::instance(),
396 &NameDirectory::registeredNameFound,
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400397 [=] (NameDirectory::LookupStatus status,
398 const QString& address, const QString& name) {
Alexandre Lision882289b2016-10-31 16:10:39 -0400399 NSLog(@"Name lookup ended");
400 lookupQueued = NO;
401 //If this is the username we are waiting for, we can disconnect.
402 if (name.compare(QString::fromNSString(usernameWaitingForLookupResult)) == 0) {
403 QObject::disconnect(registeredNameFound);
404 } else {
405 //Keep waiting...
406 return;
407 }
408
409 //We may now stop the spinner
410 [self hideLookupSpinner];
411
412 BOOL isAvailable = NO;
413 NSString* message;
414 switch(status)
415 {
416 case NameDirectory::LookupStatus::SUCCESS:
417 {
418 message = NSLocalizedString(@"The entered username is not available",
419 @"Text shown to user when his username is already registered");
420 isAvailable = NO;
421 break;
422 }
423 case NameDirectory::LookupStatus::NOT_FOUND:
424 {
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400425 message = @"";
Alexandre Lision882289b2016-10-31 16:10:39 -0400426 isAvailable = YES;
427 break;
428 }
429 case NameDirectory::LookupStatus::INVALID_NAME:
430 {
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400431 message = NSLocalizedString(@"Invalid username.",
Alexandre Lision882289b2016-10-31 16:10:39 -0400432 @"Text shown to user when his username is invalid to be registered");
433 isAvailable = NO;
434 break;
435 }
436 case NameDirectory::LookupStatus::ERROR:
437 default:
438 {
439 message = NSLocalizedString(@"Failed to perform lookup",
440 @"Text shown to user when an error occur at registration");
441 isAvailable = NO;
442 break;
443 }
444 }
445 [self showLookUpAvailable:isAvailable andText: message];
446 [self onUsernameAvailabilityChangedWithNewAvailability:isAvailable];
447
448 });
449
450 //Start the lookup in a second so that the UI dosen't seem to freeze
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400451 BOOL result = NameDirectory::instance().lookupName(QString(), QString::fromNSString(usernameWaitingForLookupResult));
Alexandre Lision882289b2016-10-31 16:10:39 -0400452
453}
454
Alexandre Lision5dc5d312016-11-10 10:41:37 -0500455#pragma mark - NSTextFieldDelegate delegate methods
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400456
Alexandre Lision882289b2016-10-31 16:10:39 -0400457- (void)controlTextDidChange:(NSNotification *)notif
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400458{
459 NSTextField* textField = [notif object];
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400460 if (textField.tag == PASSWORD_TAG) {
461 NSError *error = nil;
462 [self validatePassword: &error];
463 return;
464 }
465 if (textField.tag == REPEAT_PASSWORD_TAG) {
466 NSError *error = nil;
467 [self validateRepeatPassword: &error];
468 return;
469 }
Alexandre Lision882289b2016-10-31 16:10:39 -0400470 if (textField.tag != BLOCKCHAIN_NAME_TAG) {
471 return;
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400472 }
Alexandre Lision882289b2016-10-31 16:10:39 -0400473 NSString* alias = textField.stringValue;
Alexandre Lision882289b2016-10-31 16:10:39 -0400474 [self showLookupSpinner];
475 [self onUsernameAvailabilityChangedWithNewAvailability:NO];
476 [NSObject cancelPreviousPerformRequestsWithTarget:self];
477 [self performSelector:@selector(lookUp:) withObject:alias afterDelay:0.5];
478}
479
480- (void) lookUp:(NSString*) name
481{
482 if (self.withBlockchain && !lookupQueued) {
483 usernameWaitingForLookupResult = name;
484 lookupQueued = YES;
485 [self lookupUserName];
486 }
487}
488
489
490+ (NSSet *)keyPathsForValuesAffectingUserNameAvailableORNotBlockchain
491{
492 return [NSSet setWithObjects: NSStringFromSelector(@selector(signUpBlockchainState)),
493 NSStringFromSelector(@selector(isUserNameAvailable)),
494 nil];
495}
496
497+ (NSSet *)keyPathsForValuesAffectingWithBlockchain
498{
499 return [NSSet setWithObjects: NSStringFromSelector(@selector(signUpBlockchainState)),
500 nil];
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400501}
502
Loïc Siret3652cfb2016-10-27 10:12:07 -0400503+ (NSSet *)keyPathsForValuesAffectingIsPasswordValid
504{
505 return [NSSet setWithObjects:@"password", nil];
506}
507
508+ (NSSet *)keyPathsForValuesAffectingIsRepeatPasswordValid
509{
510 return [NSSet setWithObjects:@"password", @"repeatPassword", nil];
511}
Loïc Siretfcb4ca62016-09-21 17:12:09 -0400512@end