blob: 063018f4c726510fe10bc08e6c5dea89b555c639 [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
24#import <AddressBook/AddressBook.h>
25
26//LRC
27#import <accountmodel.h>
28#import <QItemSelectionModel>
29#import <account.h>
30
31#import "AppDelegate.h"
32
33@interface RegisterNameWC ()
34@end
35
36@implementation RegisterNameWC
37{
38 __unsafe_unretained IBOutlet NSTextField* registeredNameField;
39 __unsafe_unretained IBOutlet NSSecureTextField* passwordField;
40 __unsafe_unretained IBOutlet NSImageView* ivLookupResult;
41 __unsafe_unretained IBOutlet NSProgressIndicator* indicatorLookupResult;
42
43 __unsafe_unretained IBOutlet NSProgressIndicator *registrationProgress;
44
45 QMetaObject::Connection registrationEnded;
46 QMetaObject::Connection registeredNameFound;
47
48 BOOL lookupQueued;
49 NSString* usernameWaitingForLookupResult;
50}
51
52NSInteger const BLOCKCHAIN_NAME_TAG = 2;
53
54- (id)initWithDelegate:(id <LoadingWCDelegate>) del
55{
56 return [self initWithDelegate:del actionCode:0];
57}
58
59- (id)initWithDelegate:(id <RegisterNameDelegate>) del actionCode:(NSInteger) code
60{
61 return [super initWithWindowNibName:@"RegisterNameWindow" delegate:del actionCode:code];
62}
63
64- (void)windowDidLoad
65{
66 [super windowDidLoad];
67 [registeredNameField setTag:BLOCKCHAIN_NAME_TAG];
68 self.registeredName = @"";
69 [ivLookupResult setHidden:YES];
70 [indicatorLookupResult setHidden:YES];
71}
72
73#pragma mark - Input validation
74
75- (BOOL)isPasswordValid
76{
77 return self.password.length >= 6;
78}
79
80#pragma mark - Username validation delegate methods
81
82- (BOOL)userNameAvailable
83{
84 return (self.registeredName.length > 0 && self.isUserNameAvailable);
85}
86
87- (void)showLookUpAvailable:(BOOL)available andText:(NSString *)message
88{
89 [ivLookupResult setImage:[NSImage imageNamed:(available?@"ic_action_accept":@"ic_action_cancel")]] ;
90 [ivLookupResult setHidden:NO];
91 [ivLookupResult setToolTip:message];
92}
93
94- (void)onUsernameAvailabilityChangedWithNewAvailability:(BOOL)newAvailability
95{
96 self.isUserNameAvailable = newAvailability;
97}
98
99- (void)hideLookupSpinner
100{
101 [indicatorLookupResult setHidden:YES];
102}
103
104- (void)showLookupSpinner
105{
106 [ivLookupResult setHidden:YES];
107 [indicatorLookupResult setHidden:NO];
108 [indicatorLookupResult startAnimation:nil];
109}
110
111- (BOOL)lookupUserName
112{
113 [self showLookupSpinner];
114 QObject::disconnect(registeredNameFound);
115 registeredNameFound = QObject::connect(
116 &NameDirectory::instance(),
117 &NameDirectory::registeredNameFound,
118 [=] ( const Account* account, NameDirectory::LookupStatus status, const QString& address, const QString& name) {
119 NSLog(@"Name lookup ended");
120 lookupQueued = NO;
121 //If this is the username we are waiting for, we can disconnect.
122 if (name.compare(QString::fromNSString(usernameWaitingForLookupResult)) == 0) {
123 QObject::disconnect(registeredNameFound);
124 } else {
125 //Keep waiting...
126 return;
127 }
128
129 //We may now stop the spinner
130 [self hideLookupSpinner];
131
132 BOOL isAvailable = NO;
133 NSString* message;
134 switch(status)
135 {
136 case NameDirectory::LookupStatus::SUCCESS:
137 {
138 message = NSLocalizedString(@"The entered username is not available",
139 @"Text shown to user when his username is already registered");
140 isAvailable = NO;
141 break;
142 }
143 case NameDirectory::LookupStatus::NOT_FOUND:
144 {
145 message = NSLocalizedString(@"The entered username is available",
146 @"Text shown to user when his username is available to be registered");
147 isAvailable = YES;
148 break;
149 }
150 case NameDirectory::LookupStatus::INVALID_NAME:
151 {
152 message = NSLocalizedString(@"The entered username is invalid. It must have at leat 3 characters and contains only lowercase alphanumeric characters.",
153 @"Text shown to user when his username is invalid to be registered");
154 isAvailable = NO;
155 break;
156 }
157 case NameDirectory::LookupStatus::ERROR:
158 default:
159 {
160 message = NSLocalizedString(@"Failed to perform lookup",
161 @"Text shown to user when an error occur at registration");
162 isAvailable = NO;
163 break;
164 }
165 }
166 [self showLookUpAvailable:isAvailable andText: message];
167 [self onUsernameAvailabilityChangedWithNewAvailability:isAvailable];
168
169 }
170 );
171
172 //Start the lookup in a second so that the UI dosen't seem to freeze
173 BOOL result = NameDirectory::instance().lookupName(nullptr, QString(), QString::fromNSString(usernameWaitingForLookupResult));
174
175}
176
177- (void)controlTextDidChange:(NSNotification *)notif
178{
179 NSTextField* textField = [notif object];
180 if (textField.tag != BLOCKCHAIN_NAME_TAG) {
181 return;
182 }
183 NSString* alias = textField.stringValue;
184
185 [self showLookupSpinner];
186 [self onUsernameAvailabilityChangedWithNewAvailability:NO];
187 [NSObject cancelPreviousPerformRequestsWithTarget:self];
188 [self performSelector:@selector(lookUp:) withObject:alias afterDelay:0.5];
189}
190
191- (void) lookUp:(NSString*) name
192{
193 if (!lookupQueued) {
194 usernameWaitingForLookupResult = name;
195 lookupQueued = YES;
196 [self lookupUserName];
197 }
198}
199
200#pragma mark - Registration process
201
202- (IBAction)registerUsername:(id)sender
203{
204 [registrationProgress startAnimation:nil];
205 [self showLoading];
206 [self setCallback];
207
208 self.isUserNameAvailable = AccountModel::instance().selectedAccount()->registerName(QString::fromNSString(self.password),
209 QString::fromNSString(self.registeredName));
210 if (!self.isUserNameAvailable) {
211 NSLog(@"Could not initialize registerName operation");
212 QObject::disconnect(registrationEnded);
213 }
214}
215
216- (void)setCallback
217{
218 QObject::disconnect(registrationEnded);
219 registrationEnded = QObject::connect(AccountModel::instance().selectedAccount(),
220 &Account::nameRegistrationEnded,
221 [=] (NameDirectory::RegisterNameStatus status, const QString& name)
222 {
223 QObject::disconnect(registrationEnded);
224 switch(status) {
225 case NameDirectory::RegisterNameStatus::WRONG_PASSWORD:
226 case NameDirectory::RegisterNameStatus::ALREADY_TAKEN:
227 case NameDirectory::RegisterNameStatus::NETWORK_ERROR:
228 [self showError];
229 break;
230 case NameDirectory::RegisterNameStatus::SUCCESS:
231 [self.delegate didRegisterNameWithSuccess];
232 break;
233 }
234 });
235}
236
237
238+ (NSSet *)keyPathsForValuesAffectingUserNameAvailableORNotBlockchain
239{
240 return [NSSet setWithObjects: NSStringFromSelector(@selector(isUserNameAvailable)), nil];
241}
242
243+ (NSSet *)keyPathsForValuesAffectingIsPasswordValid
244{
245 return [NSSet setWithObjects:@"password", nil];
246}
247
248@end