UI/UX: name registration

Currently application can be used right after account creation.
It could be confused for user because name registration will be
finished after or failed at all. This patch ensure that application
receive registering name answer before completing account creation
process. This could introduce longer time for account creation
but user would have better understanding of account state.

Change-Id: I317b98624b1943bddb35859557beed9160016023
diff --git a/Ring/Ring/Constants/Generated/Strings.swift b/Ring/Ring/Constants/Generated/Strings.swift
index daed9ab..6ee9e2f 100644
--- a/Ring/Ring/Constants/Generated/Strings.swift
+++ b/Ring/Ring/Constants/Generated/Strings.swift
@@ -251,6 +251,10 @@
     internal static let repeatPasswordPlaceholder = L10n.tr("Localizable", "createAccount.repeatPasswordPlaceholder")
     /// username already taken
     internal static let usernameAlreadyTaken = L10n.tr("Localizable", "createAccount.usernameAlreadyTaken")
+    /// Account was created but username was not registered
+    internal static let usernameNotRegisteredMessage = L10n.tr("Localizable", "createAccount.UsernameNotRegisteredMessage")
+    /// Network error
+    internal static let usernameNotRegisteredTitle = L10n.tr("Localizable", "createAccount.UsernameNotRegisteredTitle")
     /// Adding account
     internal static let waitCreateAccountTitle = L10n.tr("Localizable", "createAccount.waitCreateAccountTitle")
   }
diff --git a/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewController.swift b/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewController.swift
index 979af15..64d8ee3 100644
--- a/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewController.swift
+++ b/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewController.swift
@@ -205,6 +205,9 @@
                 self?.showAccountCreationInProgress()
             case .success:
                 self?.hideAccountCreationHud()
+            case .nameNotRegistered:
+                self?.hideAccountCreationHud()
+                self?.showNameNotRegistered()
             default:
                 self?.hideAccountCreationHud()
             }
@@ -285,4 +288,18 @@
         alert.addAction(UIAlertAction.init(title: L10n.Global.ok, style: .default, handler: nil))
         self.present(alert, animated: true, completion: nil)
     }
+
+    private func showNameNotRegistered() {
+        let alert = UIAlertController
+            .init(title: L10n.CreateAccount.usernameNotRegisteredTitle,
+                  message: L10n.CreateAccount.usernameNotRegisteredMessage,
+                  preferredStyle: .alert)
+        let okAction =
+            UIAlertAction(title: L10n.Global.ok,
+                          style: .default) { [weak self](_: UIAlertAction!) -> Void in
+                            self?.viewModel.finish()
+        }
+        alert.addAction(okAction)
+        self.present(alert, animated: true, completion: nil)
+    }
 }
diff --git a/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewModel.swift b/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewModel.swift
index a1fd639..3af55e2 100644
--- a/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewModel.swift
+++ b/Ring/Ring/Features/Walkthrough/CreateAccount/CreateAccountViewModel.swift
@@ -79,6 +79,7 @@
     case unknown
     case started
     case success
+    case nameNotRegistered
     case error(error: AccountCreationError)
 
     var isInProgress: Bool {
@@ -268,15 +269,33 @@
         let password = self.password.value
 
         self.accountService
-            .addRingAccount(username: username, password: password, enable: self.notificationSwitch.value)
+            .addRingAccount(username: username,
+                            password: password,
+                            enable: self.notificationSwitch.value)
             .subscribe(onNext: { [unowned self] (account) in
-                self.accountCreationState.value = .success
-                DispatchQueue.main.async {
-                    self.stateSubject.onNext(WalkthroughState.accountCreated)
+                if username.isEmpty {
+                    self.accountCreationState.value = .success
+                    DispatchQueue.main.async {
+                        self.stateSubject.onNext(WalkthroughState.accountCreated)
+                    }
+                    return
                 }
-                self.nameService.registerName(withAccount: account.id,
-                                              password: password,
-                                              name: username)
+                self.nameService.registerNameObservable(withAccount: account.id,
+                                                        password: password,
+                                                        name: username)
+                    .subscribe(onNext: { registered in
+                        if registered {
+                            self.accountCreationState.value = .success
+                            DispatchQueue.main.async {
+                                self.stateSubject
+                                    .onNext(WalkthroughState.accountCreated)
+                            }
+                        } else {
+                            self.accountCreationState.value = .nameNotRegistered
+                        }
+                    }, onError: { _ in
+                        self.accountCreationState.value = .nameNotRegistered
+                    }).disposed(by: self.disposeBag)
                 }, onError: { [unowned self] (error) in
                     if let error = error as? AccountCreationError {
                         self.accountCreationState.value = .error(error: error)
@@ -288,6 +307,10 @@
         self.enablePushNotifications(enable: self.notificationSwitch.value)
     }
 
+    func finish() {
+        self.stateSubject.onNext(WalkthroughState.accountCreated)
+    }
+
     func enablePushNotifications(enable: Bool) {
         if !enable {
             return
diff --git a/Ring/Ring/Resources/en.lproj/Localizable.strings b/Ring/Ring/Resources/en.lproj/Localizable.strings
index ef7c165..f3182be 100644
--- a/Ring/Ring/Resources/en.lproj/Localizable.strings
+++ b/Ring/Ring/Resources/en.lproj/Localizable.strings
@@ -84,6 +84,8 @@
 "createAccount.PasswordInformation" = "Choose a password to encrypt your local account. Don’t forget it or you will not be able to recover your account";
 "createAccount.EnableNotifications" = "Notifications";
 "createAccount.Recommended" = "(Recommended)";
+"createAccount.UsernameNotRegisteredTitle" = "Network error";
+"createAccount.UsernameNotRegisteredMessage" = "Account was created but username was not registered";
 
 //Link To Account form
 "linkToAccount.waitLinkToAccountTitle" = "Account linking";
diff --git a/Ring/Ring/Services/NameService.swift b/Ring/Ring/Services/NameService.swift
index b16c102..106a632 100644
--- a/Ring/Ring/Services/NameService.swift
+++ b/Ring/Ring/Services/NameService.swift
@@ -53,9 +53,12 @@
      Status of the current username validation request
      */
     var usernameValidationStatus = PublishSubject<UsernameValidationStatus>()
+    fileprivate let registrationStatus = PublishSubject<ServiceEvent>()
+    var sharedRegistrationStatus: Observable<ServiceEvent>
 
     init(withNameRegistrationAdapter nameRegistrationAdapter: NameRegistrationAdapter) {
         self.nameRegistrationAdapter = nameRegistrationAdapter
+        self.sharedRegistrationStatus = registrationStatus.share()
         NameRegistrationAdapter.delegate = self
     }
 
@@ -103,6 +106,39 @@
         self.nameRegistrationAdapter.registerName(withAccount: account, password: password, name: name)
     }
 
+    func registerNameObservable(withAccount account: String, password: String, name: String)-> Observable<Bool> {
+        let registerName: Single<Bool> =
+            Single.create(subscribe: { (single) -> Disposable in
+        self.nameRegistrationAdapter
+            .registerName(withAccount: account,
+                          password: password,
+                          name: name)
+            single(.success(true))
+            return Disposables.create {
+            }
+        })
+
+        let filteredDaemonSignals = self.sharedRegistrationStatus
+            .filter { (serviceEvent) -> Bool in
+                if serviceEvent.getEventInput(ServiceEventInput.accountId) != account {return false}
+                if serviceEvent.eventType != .nameRegistrationEnded {
+                    return false
+                }
+                return true
+        }
+        return Observable
+            .combineLatest(registerName.asObservable(), filteredDaemonSignals.asObservable()) { (_, serviceEvent) -> Bool in
+                guard let status: NameRegistrationState = serviceEvent.getEventInput(ServiceEventInput.state)
+                    else {return false}
+                switch status {
+                case .success:
+                    return true
+                default:
+                    return false
+                }
+            }
+    }
+
     // MARK: NameService delegate
 
     internal func registeredNameFound(with response: LookupNameResponse) {
@@ -132,5 +168,9 @@
         } else {
             log.debug("Name Registration failed. State = \(response.state.rawValue)")
         }
+        var event = ServiceEvent(withEventType: .nameRegistrationEnded)
+        event.addEventInput(.state, value: response.state)
+        event.addEventInput(.accountId, value: response.accountId)
+        self.registrationStatus.onNext(event)
     }
 }
diff --git a/Ring/Ring/Services/ServiceEvent.swift b/Ring/Ring/Services/ServiceEvent.swift
index cb28b1d..0834fbc 100644
--- a/Ring/Ring/Services/ServiceEvent.swift
+++ b/Ring/Ring/Services/ServiceEvent.swift
@@ -43,6 +43,7 @@
     case dataTransferMessageUpdated
     case deviceRevocationEnded
     case newIncomingMessage
+    case nameRegistrationEnded
 }
 
 /**