blob: 0fc1df3cb7de89e5abbda3046dd4ac12a9c964d4 [file] [log] [blame]
Alexandre Lision34079c22016-10-31 16:14:02 -04001/*
Sébastien Blin029ffa82019-01-02 17:43:48 -05002 * Copyright (C) 2016-2019 Savoir-faire Linux Inc.
Alexandre Lision34079c22016-10-31 16:14:02 -04003 * 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
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040020#import <Cocoa/Cocoa.h>
21
Alexandre Lision34079c22016-10-31 16:14:02 -040022#import "RegisterNameWC.h"
Alexandre Lision34079c22016-10-31 16:14:02 -040023#import "AppDelegate.h"
24
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040025//LRC
26#import <api/lrc.h>
27#import <api/newaccountmodel.h>
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -040028#import <api/account.h>
29#import <namedirectory.h>
Alexandre Lision34079c22016-10-31 16:14:02 -040030
31@implementation RegisterNameWC
32{
33 __unsafe_unretained IBOutlet NSTextField* registeredNameField;
Kateryna Kostiuk6495de82019-04-19 13:49:24 -040034 __unsafe_unretained IBOutlet NSSecureTextField* passwordField;
35 __unsafe_unretained IBOutlet NSTextField* passwordLabel;
36 __unsafe_unretained IBOutlet NSLayoutConstraint* passwordTopConstraint;
Alexandre Lision34079c22016-10-31 16:14:02 -040037 __unsafe_unretained IBOutlet NSImageView* ivLookupResult;
38 __unsafe_unretained IBOutlet NSProgressIndicator* indicatorLookupResult;
39
40 __unsafe_unretained IBOutlet NSProgressIndicator *registrationProgress;
41
42 QMetaObject::Connection registrationEnded;
43 QMetaObject::Connection registeredNameFound;
44
45 BOOL lookupQueued;
Kateryna Kostiuk6495de82019-04-19 13:49:24 -040046 BOOL needPassword;
Alexandre Lision34079c22016-10-31 16:14:02 -040047 NSString* usernameWaitingForLookupResult;
48}
49
50NSInteger const BLOCKCHAIN_NAME_TAG = 2;
Kateryna Kostiuk6495de82019-04-19 13:49:24 -040051NSInteger const PASSWORD_TAG = 3;
Alexandre Lision34079c22016-10-31 16:14:02 -040052
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040053@synthesize accountModel;
Alexandre Lision34079c22016-10-31 16:14:02 -040054
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040055-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(lrc::api::NewAccountModel*) accountModel
Alexandre Lision34079c22016-10-31 16:14:02 -040056{
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040057 if (self = [self initWithWindowNibName:nibNameOrNil])
58 {
59 self.accountModel= accountModel;
60 }
61 return self;
Alexandre Lision34079c22016-10-31 16:14:02 -040062}
63
64- (void)windowDidLoad
65{
66 [super windowDidLoad];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040067 auto accounts = self.accountModel->getAccountList();
Kateryna Kostiuk6495de82019-04-19 13:49:24 -040068 lrc::api::account::ConfProperties_t accountProperties = self.accountModel->getAccountConfig(self.selectedAccountID);
69 needPassword = accountProperties.archiveHasPassword;
70 [passwordField setHidden: !needPassword];
71 [passwordLabel setHidden: !needPassword];
72 passwordTopConstraint.constant = needPassword ? 20.0 : -20.0;
Alexandre Lision34079c22016-10-31 16:14:02 -040073 [registeredNameField setTag:BLOCKCHAIN_NAME_TAG];
Alexandre Lision34079c22016-10-31 16:14:02 -040074 [ivLookupResult setHidden:YES];
75 [indicatorLookupResult setHidden:YES];
Alexandre Lision34079c22016-10-31 16:14:02 -040076}
77
78#pragma mark - Username validation delegate methods
79
80- (BOOL)userNameAvailable
81{
Kateryna Kostiukbdaa2742018-09-04 15:49:30 -040082 return (registeredNameField.stringValue.length > 0 && self.isUserNameAvailable);
Alexandre Lision34079c22016-10-31 16:14:02 -040083}
84
85- (void)showLookUpAvailable:(BOOL)available andText:(NSString *)message
86{
87 [ivLookupResult setImage:[NSImage imageNamed:(available?@"ic_action_accept":@"ic_action_cancel")]] ;
88 [ivLookupResult setHidden:NO];
89 [ivLookupResult setToolTip:message];
90}
91
92- (void)onUsernameAvailabilityChangedWithNewAvailability:(BOOL)newAvailability
93{
94 self.isUserNameAvailable = newAvailability;
Kateryna Kostiuk6495de82019-04-19 13:49:24 -040095
96 self.couldRegister = needPassword ?
97 self.isUserNameAvailable && [self.passwordString length] > 0 :
98 self.isUserNameAvailable;
Alexandre Lision34079c22016-10-31 16:14:02 -040099}
100
101- (void)hideLookupSpinner
102{
103 [indicatorLookupResult setHidden:YES];
104}
105
106- (void)showLookupSpinner
107{
108 [ivLookupResult setHidden:YES];
109 [indicatorLookupResult setHidden:NO];
110 [indicatorLookupResult startAnimation:nil];
111}
112
113- (BOOL)lookupUserName
114{
115 [self showLookupSpinner];
116 QObject::disconnect(registeredNameFound);
117 registeredNameFound = QObject::connect(
118 &NameDirectory::instance(),
119 &NameDirectory::registeredNameFound,
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400120 [=] (NameDirectory::LookupStatus status,
121 const QString& address, const QString& name) {
Alexandre Lision34079c22016-10-31 16:14:02 -0400122 NSLog(@"Name lookup ended");
123 lookupQueued = NO;
124 //If this is the username we are waiting for, we can disconnect.
125 if (name.compare(QString::fromNSString(usernameWaitingForLookupResult)) == 0) {
126 QObject::disconnect(registeredNameFound);
127 } else {
128 //Keep waiting...
129 return;
130 }
131
132 //We may now stop the spinner
133 [self hideLookupSpinner];
134
135 BOOL isAvailable = NO;
136 NSString* message;
137 switch(status)
138 {
139 case NameDirectory::LookupStatus::SUCCESS:
140 {
141 message = NSLocalizedString(@"The entered username is not available",
142 @"Text shown to user when his username is already registered");
143 isAvailable = NO;
144 break;
145 }
146 case NameDirectory::LookupStatus::NOT_FOUND:
147 {
148 message = NSLocalizedString(@"The entered username is available",
149 @"Text shown to user when his username is available to be registered");
150 isAvailable = YES;
151 break;
152 }
153 case NameDirectory::LookupStatus::INVALID_NAME:
154 {
Kateryna Kostiukc7e68f32019-10-09 16:15:45 -0400155 message = NSLocalizedString(@"Invalid username",
Alexandre Lision34079c22016-10-31 16:14:02 -0400156 @"Text shown to user when his username is invalid to be registered");
157 isAvailable = NO;
158 break;
159 }
160 case NameDirectory::LookupStatus::ERROR:
161 default:
162 {
163 message = NSLocalizedString(@"Failed to perform lookup",
164 @"Text shown to user when an error occur at registration");
165 isAvailable = NO;
166 break;
167 }
168 }
169 [self showLookUpAvailable:isAvailable andText: message];
170 [self onUsernameAvailabilityChangedWithNewAvailability:isAvailable];
Alexandre Lision34079c22016-10-31 16:14:02 -0400171 }
172 );
173
174 //Start the lookup in a second so that the UI dosen't seem to freeze
Kateryna Kostiukbe7e2e42019-07-26 17:44:12 -0400175 BOOL result = NameDirectory::instance().lookupName(QString(), QString::fromNSString(usernameWaitingForLookupResult));
Alexandre Lision34079c22016-10-31 16:14:02 -0400176}
177
178- (void)controlTextDidChange:(NSNotification *)notif
179{
180 NSTextField* textField = [notif object];
Kateryna Kostiuk6495de82019-04-19 13:49:24 -0400181 if (textField.tag == BLOCKCHAIN_NAME_TAG) {
182 NSString* alias = textField.stringValue;
Alexandre Lision34079c22016-10-31 16:14:02 -0400183
Kateryna Kostiuk6495de82019-04-19 13:49:24 -0400184 [self showLookupSpinner];
185 [self onUsernameAvailabilityChangedWithNewAvailability:NO];
186 [NSObject cancelPreviousPerformRequestsWithTarget:self];
187 [self performSelector:@selector(lookUp:) withObject:alias afterDelay:0.5];
188 } else if (textField.tag == PASSWORD_TAG) {
189 self.couldRegister = needPassword ?
190 self.isUserNameAvailable && [self.passwordString length] > 0 :
191 self.isUserNameAvailable;
192 }
Alexandre Lision34079c22016-10-31 16:14:02 -0400193}
194
195- (void) lookUp:(NSString*) name
196{
197 if (!lookupQueued) {
198 usernameWaitingForLookupResult = name;
199 lookupQueued = YES;
200 [self lookupUserName];
201 }
202}
203
204#pragma mark - Registration process
205
206- (IBAction)registerUsername:(id)sender
207{
Kateryna Kostiuk6495de82019-04-19 13:49:24 -0400208 NSString *password = passwordField.stringValue;
209 if((!password || [password length] == 0) && needPassword) {
210 return;
211 }
Alexandre Lision34079c22016-10-31 16:14:02 -0400212 [registrationProgress startAnimation:nil];
213 [self showLoading];
214 [self setCallback];
215
Kateryna Kostiuk6495de82019-04-19 13:49:24 -0400216 self.isUserNameAvailable = self.accountModel->registerName(self.selectedAccountID,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400217 QString::fromNSString(password),
218 QString::fromNSString(registeredNameField.stringValue));
Alexandre Lision34079c22016-10-31 16:14:02 -0400219 if (!self.isUserNameAvailable) {
220 NSLog(@"Could not initialize registerName operation");
221 QObject::disconnect(registrationEnded);
222 }
223}
224
225- (void)setCallback
226{
227 QObject::disconnect(registrationEnded);
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400228 registrationEnded = QObject::connect(self.accountModel,
229 &lrc::api::NewAccountModel::nameRegistrationEnded,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400230 [self] (const QString& accountId, lrc::api::account::RegisterNameStatus status, const QString& name) {
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400231 if(accountId.compare(self.selectedAccountID) != 0) {
232 return;
233 }
234 switch(status)
235 {
236 case lrc::api::account::RegisterNameStatus::SUCCESS: {
Kateryna Kostiukbdaa2742018-09-04 15:49:30 -0400237 [self.delegate didRegisterName: registeredNameField.stringValue withSuccess: YES];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400238 break;
239 }
240 case lrc::api::account::RegisterNameStatus::INVALID_NAME:
241 case lrc::api::account::RegisterNameStatus::WRONG_PASSWORD:
242 case lrc::api::account::RegisterNameStatus::NETWORK_ERROR:
243 case lrc::api::account::RegisterNameStatus::ALREADY_TAKEN: {
Alexandre Lision34079c22016-10-31 16:14:02 -0400244 [self showError];
245 break;
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400246 }
Alexandre Lision34079c22016-10-31 16:14:02 -0400247 }
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -0400248 QObject::disconnect(registrationEnded);
Alexandre Lision34079c22016-10-31 16:14:02 -0400249 });
250}
251
252
253+ (NSSet *)keyPathsForValuesAffectingUserNameAvailableORNotBlockchain
254{
255 return [NSSet setWithObjects: NSStringFromSelector(@selector(isUserNameAvailable)), nil];
256}
257
Alexandre Lision34079c22016-10-31 16:14:02 -0400258
259@end