blob: 1402fcc450bf925be895a4c908f3bc176abcbc23 [file] [log] [blame]
Alexandre Lision34079c22016-10-31 16:14:02 -04001/*
2 * Copyright (C) 2016 Savoir-faire Linux Inc.
3 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#import "RegisterNameWC.h"
21
22
23//Cocoa
Alexandre Lision34079c22016-10-31 16:14:02 -040024
25//LRC
26#import <accountmodel.h>
27#import <QItemSelectionModel>
28#import <account.h>
29
30#import "AppDelegate.h"
31
32@interface RegisterNameWC ()
33@end
34
35@implementation RegisterNameWC
36{
37 __unsafe_unretained IBOutlet NSTextField* registeredNameField;
38 __unsafe_unretained IBOutlet NSSecureTextField* passwordField;
39 __unsafe_unretained IBOutlet NSImageView* ivLookupResult;
40 __unsafe_unretained IBOutlet NSProgressIndicator* indicatorLookupResult;
41
42 __unsafe_unretained IBOutlet NSProgressIndicator *registrationProgress;
43
44 QMetaObject::Connection registrationEnded;
45 QMetaObject::Connection registeredNameFound;
46
47 BOOL lookupQueued;
48 NSString* usernameWaitingForLookupResult;
49}
50
51NSInteger const BLOCKCHAIN_NAME_TAG = 2;
52
53- (id)initWithDelegate:(id <LoadingWCDelegate>) del
54{
55 return [self initWithDelegate:del actionCode:0];
56}
57
58- (id)initWithDelegate:(id <RegisterNameDelegate>) del actionCode:(NSInteger) code
59{
60 return [super initWithWindowNibName:@"RegisterNameWindow" delegate:del actionCode:code];
61}
62
63- (void)windowDidLoad
64{
65 [super windowDidLoad];
66 [registeredNameField setTag:BLOCKCHAIN_NAME_TAG];
67 self.registeredName = @"";
68 [ivLookupResult setHidden:YES];
69 [indicatorLookupResult setHidden:YES];
70}
71
72#pragma mark - Input validation
73
74- (BOOL)isPasswordValid
75{
76 return self.password.length >= 6;
77}
78
79#pragma mark - Username validation delegate methods
80
81- (BOOL)userNameAvailable
82{
83 return (self.registeredName.length > 0 && self.isUserNameAvailable);
84}
85
86- (void)showLookUpAvailable:(BOOL)available andText:(NSString *)message
87{
88 [ivLookupResult setImage:[NSImage imageNamed:(available?@"ic_action_accept":@"ic_action_cancel")]] ;
89 [ivLookupResult setHidden:NO];
90 [ivLookupResult setToolTip:message];
91}
92
93- (void)onUsernameAvailabilityChangedWithNewAvailability:(BOOL)newAvailability
94{
95 self.isUserNameAvailable = newAvailability;
96}
97
98- (void)hideLookupSpinner
99{
100 [indicatorLookupResult setHidden:YES];
101}
102
103- (void)showLookupSpinner
104{
105 [ivLookupResult setHidden:YES];
106 [indicatorLookupResult setHidden:NO];
107 [indicatorLookupResult startAnimation:nil];
108}
109
110- (BOOL)lookupUserName
111{
112 [self showLookupSpinner];
113 QObject::disconnect(registeredNameFound);
114 registeredNameFound = QObject::connect(
115 &NameDirectory::instance(),
116 &NameDirectory::registeredNameFound,
117 [=] ( const Account* account, NameDirectory::LookupStatus status, const QString& address, const QString& name) {
118 NSLog(@"Name lookup ended");
119 lookupQueued = NO;
120 //If this is the username we are waiting for, we can disconnect.
121 if (name.compare(QString::fromNSString(usernameWaitingForLookupResult)) == 0) {
122 QObject::disconnect(registeredNameFound);
123 } else {
124 //Keep waiting...
125 return;
126 }
127
128 //We may now stop the spinner
129 [self hideLookupSpinner];
130
131 BOOL isAvailable = NO;
132 NSString* message;
133 switch(status)
134 {
135 case NameDirectory::LookupStatus::SUCCESS:
136 {
137 message = NSLocalizedString(@"The entered username is not available",
138 @"Text shown to user when his username is already registered");
139 isAvailable = NO;
140 break;
141 }
142 case NameDirectory::LookupStatus::NOT_FOUND:
143 {
144 message = NSLocalizedString(@"The entered username is available",
145 @"Text shown to user when his username is available to be registered");
146 isAvailable = YES;
147 break;
148 }
149 case NameDirectory::LookupStatus::INVALID_NAME:
150 {
Alexandre Lision5dc5d312016-11-10 10:41:37 -0500151 message = NSLocalizedString(@"The entered username is invalid. It must have at least 3 characters and contain only lowercase alphanumeric characters.",
Alexandre Lision34079c22016-10-31 16:14:02 -0400152 @"Text shown to user when his username is invalid to be registered");
153 isAvailable = NO;
154 break;
155 }
156 case NameDirectory::LookupStatus::ERROR:
157 default:
158 {
159 message = NSLocalizedString(@"Failed to perform lookup",
160 @"Text shown to user when an error occur at registration");
161 isAvailable = NO;
162 break;
163 }
164 }
165 [self showLookUpAvailable:isAvailable andText: message];
166 [self onUsernameAvailabilityChangedWithNewAvailability:isAvailable];
167
168 }
169 );
170
171 //Start the lookup in a second so that the UI dosen't seem to freeze
172 BOOL result = NameDirectory::instance().lookupName(nullptr, QString(), QString::fromNSString(usernameWaitingForLookupResult));
173
174}
175
176- (void)controlTextDidChange:(NSNotification *)notif
177{
178 NSTextField* textField = [notif object];
179 if (textField.tag != BLOCKCHAIN_NAME_TAG) {
180 return;
181 }
182 NSString* alias = textField.stringValue;
183
184 [self showLookupSpinner];
185 [self onUsernameAvailabilityChangedWithNewAvailability:NO];
186 [NSObject cancelPreviousPerformRequestsWithTarget:self];
187 [self performSelector:@selector(lookUp:) withObject:alias afterDelay:0.5];
188}
189
190- (void) lookUp:(NSString*) name
191{
192 if (!lookupQueued) {
193 usernameWaitingForLookupResult = name;
194 lookupQueued = YES;
195 [self lookupUserName];
196 }
197}
198
199#pragma mark - Registration process
200
201- (IBAction)registerUsername:(id)sender
202{
203 [registrationProgress startAnimation:nil];
204 [self showLoading];
205 [self setCallback];
206
207 self.isUserNameAvailable = AccountModel::instance().selectedAccount()->registerName(QString::fromNSString(self.password),
208 QString::fromNSString(self.registeredName));
209 if (!self.isUserNameAvailable) {
210 NSLog(@"Could not initialize registerName operation");
211 QObject::disconnect(registrationEnded);
212 }
213}
214
215- (void)setCallback
216{
217 QObject::disconnect(registrationEnded);
218 registrationEnded = QObject::connect(AccountModel::instance().selectedAccount(),
219 &Account::nameRegistrationEnded,
220 [=] (NameDirectory::RegisterNameStatus status, const QString& name)
221 {
222 QObject::disconnect(registrationEnded);
223 switch(status) {
224 case NameDirectory::RegisterNameStatus::WRONG_PASSWORD:
225 case NameDirectory::RegisterNameStatus::ALREADY_TAKEN:
226 case NameDirectory::RegisterNameStatus::NETWORK_ERROR:
227 [self showError];
228 break;
229 case NameDirectory::RegisterNameStatus::SUCCESS:
230 [self.delegate didRegisterNameWithSuccess];
Alexandre Lision313427f2016-11-24 21:04:04 -0500231 // Artificial refresh of the model to update the welcome view
232 Q_EMIT AccountModel::instance().dataChanged(QModelIndex(), QModelIndex());
Alexandre Lision34079c22016-10-31 16:14:02 -0400233 break;
234 }
235 });
236}
237
238
239+ (NSSet *)keyPathsForValuesAffectingUserNameAvailableORNotBlockchain
240{
241 return [NSSet setWithObjects: NSStringFromSelector(@selector(isUserNameAvailable)), nil];
242}
243
244+ (NSSet *)keyPathsForValuesAffectingIsPasswordValid
245{
246 return [NSSet setWithObjects:@"password", nil];
247}
248
249@end