Commit 85e4ab36 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Andreas Traczyk
Browse files

Account: link to existing



Add option to link device to an existing Ring account.

Change-Id: I730d1d354b67f001fb7826aa08a3f028cd363afb
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent e79b903d
...@@ -4,3 +4,4 @@ github "pkluz/PKHUD" ...@@ -4,3 +4,4 @@ github "pkluz/PKHUD"
github "AliSoftware/Reusable" ~> 4.0 github "AliSoftware/Reusable" ~> 4.0
github "SwiftyBeaver/SwiftyBeaver" github "SwiftyBeaver/SwiftyBeaver"
github "ViccAlexander/Chameleon" github "ViccAlexander/Chameleon"
github "andreamazz/AMPopTip"
...@@ -2,7 +2,8 @@ github "AliSoftware/Reusable" "4.0.1" ...@@ -2,7 +2,8 @@ github "AliSoftware/Reusable" "4.0.1"
github "ReactiveX/RxSwift" "3.5.0" github "ReactiveX/RxSwift" "3.5.0"
github "RxSwiftCommunity/RxDataSources" "1.0.4" github "RxSwiftCommunity/RxDataSources" "1.0.4"
github "RxSwiftCommunity/RxRealm" "0.6.0" github "RxSwiftCommunity/RxRealm" "0.6.0"
github "SwiftyBeaver/SwiftyBeaver" "1.3.0" github "SwiftyBeaver/SwiftyBeaver" "1.4.2"
github "ViccAlexander/Chameleon" "2.2.0" github "ViccAlexander/Chameleon" "2.2.0"
github "andreamazz/AMPopTip" "3.0.2"
github "pkluz/PKHUD" "4.2.3" github "pkluz/PKHUD" "4.2.3"
github "realm/realm-cocoa" "v2.8.3" github "realm/realm-cocoa" "v2.8.3"
...@@ -89,6 +89,7 @@ ...@@ -89,6 +89,7 @@
0ED2B6FA1F96A075001572F0 /* LinkNewDeviceViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */; }; 0ED2B6FA1F96A075001572F0 /* LinkNewDeviceViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */; };
0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */; }; 0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */; };
0ED2B6FE1F96A16C001572F0 /* LinkNewDeviceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */; }; 0ED2B6FE1F96A16C001572F0 /* LinkNewDeviceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */; };
0ED666101F9FED1C00743D42 /* AMPopTip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ED6660F1F9FED1C00743D42 /* AMPopTip.framework */; };
0EDCC8601F98150500B121D7 /* UIView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDCC85F1F98150500B121D7 /* UIView+Rx.swift */; }; 0EDCC8601F98150500B121D7 /* UIView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDCC85F1F98150500B121D7 /* UIView+Rx.swift */; };
0EDE34C71F868E1200FFA15C /* EditProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */; }; 0EDE34C71F868E1200FFA15C /* EditProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */; };
0EDE34C91F8691BB00FFA15C /* EditProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */; }; 0EDE34C91F8691BB00FFA15C /* EditProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */; };
...@@ -319,6 +320,7 @@ ...@@ -319,6 +320,7 @@
0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LinkNewDeviceViewController.storyboard; sourceTree = "<group>"; }; 0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LinkNewDeviceViewController.storyboard; sourceTree = "<group>"; };
0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewController.swift; sourceTree = "<group>"; }; 0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewController.swift; sourceTree = "<group>"; };
0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewModel.swift; sourceTree = "<group>"; }; 0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewModel.swift; sourceTree = "<group>"; };
0ED6660F1F9FED1C00743D42 /* AMPopTip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AMPopTip.framework; path = Carthage/Build/iOS/AMPopTip.framework; sourceTree = "<group>"; };
0EDCC85F1F98150500B121D7 /* UIView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Rx.swift"; sourceTree = "<group>"; }; 0EDCC85F1F98150500B121D7 /* UIView+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Rx.swift"; sourceTree = "<group>"; };
0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewController.swift; sourceTree = "<group>"; }; 0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewController.swift; sourceTree = "<group>"; };
0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewModel.swift; sourceTree = "<group>"; }; 0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewModel.swift; sourceTree = "<group>"; };
...@@ -450,6 +452,7 @@ ...@@ -450,6 +452,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0ED666101F9FED1C00743D42 /* AMPopTip.framework in Frameworks */,
0EEFBA3C1F83DA21000EDBAD /* libsecp256k1.a in Frameworks */, 0EEFBA3C1F83DA21000EDBAD /* libsecp256k1.a in Frameworks */,
1A3CA32B1F102BB700283748 /* Chameleon.framework in Frameworks */, 1A3CA32B1F102BB700283748 /* Chameleon.framework in Frameworks */,
1A1E476F1F0E894600EA9A36 /* SwiftyBeaver.framework in Frameworks */, 1A1E476F1F0E894600EA9A36 /* SwiftyBeaver.framework in Frameworks */,
...@@ -557,6 +560,7 @@ ...@@ -557,6 +560,7 @@
02AED8171DD4C4B000F740BA /* Frameworks */ = { 02AED8171DD4C4B000F740BA /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0ED6660F1F9FED1C00743D42 /* AMPopTip.framework */,
0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */, 0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */,
1A3CA32A1F102BB700283748 /* Chameleon.framework */, 1A3CA32A1F102BB700283748 /* Chameleon.framework */,
1A1E476E1F0E894600EA9A36 /* SwiftyBeaver.framework */, 1A1E476E1F0E894600EA9A36 /* SwiftyBeaver.framework */,
...@@ -1177,6 +1181,7 @@ ...@@ -1177,6 +1181,7 @@
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = KM95526DS8; DevelopmentTeam = KM95526DS8;
LastSwiftMigration = 0810; LastSwiftMigration = 0810;
ProvisioningStyle = Automatic;
SystemCapabilities = { SystemCapabilities = {
com.apple.BackgroundModes = { com.apple.BackgroundModes = {
enabled = 0; enabled = 0;
...@@ -1276,6 +1281,7 @@ ...@@ -1276,6 +1281,7 @@
"$(SRCROOT)/Carthage/Build/iOS/Reusable.framework", "$(SRCROOT)/Carthage/Build/iOS/Reusable.framework",
"$(SRCROOT)/Carthage/Build/iOS/SwiftyBeaver.framework", "$(SRCROOT)/Carthage/Build/iOS/SwiftyBeaver.framework",
"$(SRCROOT)/Carthage/Build/iOS/Chameleon.framework", "$(SRCROOT)/Carthage/Build/iOS/Chameleon.framework",
"$(SRCROOT)/Carthage/build/iOS/AMPopTip.framework",
); );
name = "⚙️ Copy Frameworks"; name = "⚙️ Copy Frameworks";
outputPaths = ( outputPaths = (
...@@ -1289,6 +1295,7 @@ ...@@ -1289,6 +1295,7 @@
"$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Reusable.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Reusable.framework",
"$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SwiftyBeaver.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SwiftyBeaver.framework",
"$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Chameleon.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Chameleon.framework",
"$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/AMPopTip.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
...@@ -1582,6 +1589,7 @@ ...@@ -1582,6 +1589,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = KM95526DS8; DEVELOPMENT_TEAM = KM95526DS8;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
...@@ -1597,6 +1605,7 @@ ...@@ -1597,6 +1605,7 @@
PRODUCT_BUNDLE_IDENTIFIER = cx.ring; PRODUCT_BUNDLE_IDENTIFIER = cx.ring;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Ring/Bridging/Ring-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Ring/Bridging/Ring-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_VERSION = 3.0;
...@@ -1612,6 +1621,7 @@ ...@@ -1612,6 +1621,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = KM95526DS8; DEVELOPMENT_TEAM = KM95526DS8;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
...@@ -1627,6 +1637,7 @@ ...@@ -1627,6 +1637,7 @@
PRODUCT_BUNDLE_IDENTIFIER = cx.ring; PRODUCT_BUNDLE_IDENTIFIER = cx.ring;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Ring/Bridging/Ring-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Ring/Bridging/Ring-Bridging-Header.h";
SWIFT_VERSION = 3.0; SWIFT_VERSION = 3.0;
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
...@@ -65,6 +66,7 @@ ...@@ -65,6 +66,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
typealias Image = UIImage typealias Image = UIImage
#endif #endif
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length // swiftlint:disable file_length
@available(*, deprecated, renamed: "ImageAsset") @available(*, deprecated, renamed: "ImageAsset")
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import Foundation import Foundation
import UIKit import UIKit
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length // swiftlint:disable file_length
protocol StoryboardType { protocol StoryboardType {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import Foundation import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length // swiftlint:disable file_length
// swiftlint:disable explicit_type_interface identifier_name line_length nesting type_body_length type_name // swiftlint:disable explicit_type_interface identifier_name line_length nesting type_body_length type_name
...@@ -15,18 +16,20 @@ enum L10n { ...@@ -15,18 +16,20 @@ enum L10n {
enum Alerts { enum Alerts {
/// Account Added /// Account Added
static let accountAddedTitle = L10n.tr("Localizable", "alerts.accountAddedTitle") static let accountAddedTitle = L10n.tr("Localizable", "alerts.accountAddedTitle")
/// Account couldn't be found on the Ring network. Make sure it was exported on Ring from an existing device, and that provided credentials are correct.
static let accountCannotBeFoundMessage = L10n.tr("Localizable", "alerts.accountCannotBeFoundMessage")
/// Can't find account /// Can't find account
static let accountCannotBeFoundTitle = L10n.tr("Localizable", "alerts.accountCannotBeFoundTitle") static let accountCannotBeFoundTitle = L10n.tr("Localizable", "alerts.accountCannotBeFoundTitle")
/// The account couldn't be created. /// The account couldn't be created.
static let accountDefaultErrorMessage = L10n.tr("Localizable", "alerts.accountDefaultErrorMessage") static let accountDefaultErrorMessage = L10n.tr("Localizable", "alerts.accountDefaultErrorMessage")
/// Unknown error /// Unknown error
static let accountDefaultErrorTitle = L10n.tr("Localizable", "alerts.accountDefaultErrorTitle") static let accountDefaultErrorTitle = L10n.tr("Localizable", "alerts.accountDefaultErrorTitle")
/// Linking account
static let accountLinkedTitle = L10n.tr("Localizable", "alerts.accountLinkedTitle")
/// Could not add account because Ring couldn't connect to the distributed network. Check your device connectivity. /// Could not add account because Ring couldn't connect to the distributed network. Check your device connectivity.
static let accountNoNetworkMessage = L10n.tr("Localizable", "alerts.accountNoNetworkMessage") static let accountNoNetworkMessage = L10n.tr("Localizable", "alerts.accountNoNetworkMessage")
/// Can't connect to the network /// Can't connect to the network
static let accountNoNetworkTitle = L10n.tr("Localizable", "alerts.accountNoNetworkTitle") static let accountNoNetworkTitle = L10n.tr("Localizable", "alerts.accountNoNetworkTitle")
/// Account couldn't be found on the Ring network. Make sure it was exported on Ring from an existing device, and that provided credentials are correct.
static let acountCannotBeFoundMessage = L10n.tr("Localizable", "alerts.acountCannotBeFoundMessage")
/// Cancel /// Cancel
static let profileCancelPhoto = L10n.tr("Localizable", "alerts.profileCancelPhoto") static let profileCancelPhoto = L10n.tr("Localizable", "alerts.profileCancelPhoto")
/// Take photo /// Take photo
...@@ -97,6 +100,23 @@ enum L10n { ...@@ -97,6 +100,23 @@ enum L10n {
static let title = L10n.tr("Localizable", "linkDevice.title") static let title = L10n.tr("Localizable", "linkDevice.title")
} }
enum Linktoaccount {
/// To generate the PIN code, go to the account managment settings on device that contain account you want to use. In devices settings Select "Link another device to this account". You will get the necessary PIN to complete this form. The PIN is only valid for 10 minutes.
static let explanationPinMessage = L10n.tr("Localizable", "linkToAccount.explanationPinMessage")
/// Link device
static let linkButtonTitle = L10n.tr("Localizable", "linkToAccount.linkButtonTitle")
/// Enter Password
static let passwordLabel = L10n.tr("Localizable", "linkToAccount.passwordLabel")
/// password
static let passwordPlaceholder = L10n.tr("Localizable", "linkToAccount.passwordPlaceholder")
/// Enter PIN
static let pinLabel = L10n.tr("Localizable", "linkToAccount.pinLabel")
/// PIN
static let pinPlaceholder = L10n.tr("Localizable", "linkToAccount.pinPlaceholder")
/// Account linking
static let waitLinkToAccountTitle = L10n.tr("Localizable", "linkToAccount.waitLinkToAccountTitle")
}
enum Smartlist { enum Smartlist {
/// Conversations /// Conversations
static let conversations = L10n.tr("Localizable", "smartlist.conversations") static let conversations = L10n.tr("Localizable", "smartlist.conversations")
......
...@@ -103,6 +103,7 @@ enum AccountCreationError: Error { ...@@ -103,6 +103,7 @@ enum AccountCreationError: Error {
case generic case generic
case network case network
case unknown case unknown
case linkError
} }
extension AccountCreationError: LocalizedError { extension AccountCreationError: LocalizedError {
...@@ -113,6 +114,8 @@ extension AccountCreationError: LocalizedError { ...@@ -113,6 +114,8 @@ extension AccountCreationError: LocalizedError {
return L10n.Alerts.accountCannotBeFoundTitle return L10n.Alerts.accountCannotBeFoundTitle
case .network: case .network:
return L10n.Alerts.accountNoNetworkTitle return L10n.Alerts.accountNoNetworkTitle
case .linkError:
return L10n.Alerts.accountCannotBeFoundTitle
default: default:
return L10n.Alerts.accountDefaultErrorTitle return L10n.Alerts.accountDefaultErrorTitle
} }
...@@ -124,6 +127,8 @@ extension AccountCreationError: LocalizedError { ...@@ -124,6 +127,8 @@ extension AccountCreationError: LocalizedError {
return L10n.Alerts.accountDefaultErrorMessage return L10n.Alerts.accountDefaultErrorMessage
case .network: case .network:
return L10n.Alerts.accountNoNetworkMessage return L10n.Alerts.accountNoNetworkMessage
case .linkError:
return L10n.Alerts.accountCannotBeFoundMessage
default: default:
return L10n.Alerts.accountDefaultErrorMessage return L10n.Alerts.accountDefaultErrorMessage
} }
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="1yn-Mj-8Ek"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="1yn-Mj-8Ek">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13174"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
...@@ -36,12 +37,48 @@ ...@@ -36,12 +37,48 @@
</userDefinedRuntimeAttribute> </userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</view> </view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Choose password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9AD-b5-bun">
<rect key="frame" x="36" y="165" width="137" height="25"/>
<constraints>
<constraint firstAttribute="height" constant="25" id="g3B-PW-uya"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enter pin" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VN2-rO-YYy">
<rect key="frame" x="36" y="40" width="68.5" height="25"/>
<constraints>
<constraint firstAttribute="height" constant="25" id="TAS-dT-bOV"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Password" textAlignment="natural" clearsOnBeginEditing="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="TH9-pF-YYq">
<rect key="frame" x="36" y="210" width="302" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="AeX-R9-vlN"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Pin" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Cuu-Tq-miP">
<rect key="frame" x="36" y="85" width="303" height="30"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="infoLight" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rtk-w4-zfQ">
<rect key="frame" x="124.5" y="43" width="22" height="22"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Po-6e-k14" customClass="DesignableButton" customModule="Ring" customModuleProvider="target"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Po-6e-k14" customClass="DesignableButton" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="87.5" y="313.5" width="200" height="40"/> <rect key="frame" x="87.5" y="290" width="200" height="40"/>
<color key="backgroundColor" red="0.0" green="0.29803921570000003" blue="0.37647058820000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.0" green="0.29803921570000003" blue="0.37647058820000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="200" id="m9R-vQ-tPe"/> <constraint firstAttribute="height" constant="40" id="aUU-qY-tFB"/>
<constraint firstAttribute="height" constant="40" id="uVC-dY-9Ym"/> <constraint firstAttribute="width" constant="200" id="oIL-uO-iFk"/>
</constraints> </constraints>
<state key="normal" title="Link Device"> <state key="normal" title="Link Device">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
...@@ -54,18 +91,36 @@ ...@@ -54,18 +91,36 @@
<constraints> <constraints>
<constraint firstAttribute="trailing" secondItem="Gv4-18-FVt" secondAttribute="trailing" id="1Ev-WL-COb"/> <constraint firstAttribute="trailing" secondItem="Gv4-18-FVt" secondAttribute="trailing" id="1Ev-WL-COb"/>
<constraint firstAttribute="trailing" secondItem="kur-G7-4Nq" secondAttribute="trailing" id="1U8-xt-ygk"/> <constraint firstAttribute="trailing" secondItem="kur-G7-4Nq" secondAttribute="trailing" id="1U8-xt-ygk"/>
<constraint firstItem="5Po-6e-k14" firstAttribute="centerX" secondItem="N1T-Xh-FH1" secondAttribute="centerX" id="4eR-3k-6Z2"/> <constraint firstItem="rtk-w4-zfQ" firstAttribute="bottom" secondItem="VN2-rO-YYy" secondAttribute="bottom" id="48M-BJ-5M7"/>
<constraint firstItem="Gv4-18-FVt" firstAttribute="top" secondItem="N1T-Xh-FH1" secondAttribute="top" id="5PT-u8-86G"/> <constraint firstItem="Gv4-18-FVt" firstAttribute="top" secondItem="N1T-Xh-FH1" secondAttribute="top" id="5PT-u8-86G"/>
<constraint firstItem="rtk-w4-zfQ" firstAttribute="leading" secondItem="VN2-rO-YYy" secondAttribute="trailing" constant="20" id="9tE-eh-oaC"/>
<constraint firstItem="TH9-pF-YYq" firstAttribute="top" secondItem="9AD-b5-bun" secondAttribute="bottom" constant="20" id="Cgg-Sj-c4x"/>
<constraint firstItem="GVt-PH-FqG" firstAttribute="top" secondItem="Gv4-18-FVt" secondAttribute="bottom" id="DHv-Q6-GhU"/> <constraint firstItem="GVt-PH-FqG" firstAttribute="top" secondItem="Gv4-18-FVt" secondAttribute="bottom" id="DHv-Q6-GhU"/>
<constraint firstItem="5Po-6e-k14" firstAttribute="centerX" secondItem="N1T-Xh-FH1" secondAttribute="centerX" id="DdK-br-kKZ"/>
<constraint firstItem="5Po-6e-k14" firstAttribute="top" secondItem="TH9-pF-YYq" secondAttribute="bottom" constant="50" id="FZx-BT-87Q"/>
<constraint firstItem="GVt-PH-FqG" firstAttribute="top" secondItem="kur-G7-4Nq" secondAttribute="bottom" id="Jvj-VY-Nb7"/> <constraint firstItem="GVt-PH-FqG" firstAttribute="top" secondItem="kur-G7-4Nq" secondAttribute="bottom" id="Jvj-VY-Nb7"/>
<constraint firstItem="Gv4-18-FVt" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leading" id="LiW-7Y-wcc"/> <constraint firstItem="Gv4-18-FVt" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leading" id="LiW-7Y-wcc"/>
<constraint firstItem="Cuu-Tq-miP" firstAttribute="top" secondItem="VN2-rO-YYy" secondAttribute="bottom" constant="20" id="MvO-t6-2LS"/>
<constraint firstItem="Cuu-Tq-miP" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leadingMargin" constant="20" id="PCJ-vm-jbA"/>
<constraint firstItem="TH9-pF-YYq" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leadingMargin" constant="20" id="XhT-uY-a4w"/>
<constraint firstItem="Cuu-Tq-miP" firstAttribute="centerX" secondItem="N1T-Xh-FH1" secondAttribute="centerX" id="Y9x-Wm-hls"/>
<constraint firstItem="9AD-b5-bun" firstAttribute="top" secondItem="Cuu-Tq-miP" secondAttribute="bottom" constant="50" id="ZbK-P2-lTS"/>
<constraint firstItem="5Po-6e-k14" firstAttribute="centerX" secondItem="N1T-Xh-FH1" secondAttribute="centerX" id="a6Y-pC-oVh"/>
<constraint firstItem="kur-G7-4Nq" firstAttribute="top" secondItem="N1T-Xh-FH1" secondAttribute="top" id="hSt-o1-S41"/> <constraint firstItem="kur-G7-4Nq" firstAttribute="top" secondItem="N1T-Xh-FH1" secondAttribute="top" id="hSt-o1-S41"/>
<constraint firstItem="5Po-6e-k14" firstAttribute="centerY" secondItem="N1T-Xh-FH1" secondAttribute="centerY" id="lQW-P9-Vmv"/> <constraint firstItem="VN2-rO-YYy" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leadingMargin" constant="20" id="lir-vx-FR8"/>
<constraint firstItem="9AD-b5-bun" firstAttribute="leading" secondItem="VN2-rO-YYy" secondAttribute="leading" id="pEu-Md-SRd"/>
<constraint firstItem="VN2-rO-YYy" firstAttribute="top" secondItem="jiD-fm-HFk" secondAttribute="bottom" constant="20" id="qQg-eH-gLE"/>
<constraint firstItem="kur-G7-4Nq" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leading" id="r5d-rQ-Kg3"/> <constraint firstItem="kur-G7-4Nq" firstAttribute="leading" secondItem="N1T-Xh-FH1" secondAttribute="leading" id="r5d-rQ-Kg3"/>
<constraint firstItem="TH9-pF-YYq" firstAttribute="centerX" secondItem="N1T-Xh-FH1" secondAttribute="centerX" id="xpu-85-bbk"/>
</constraints> </constraints>
</view> </view>
<connections> <connections>
<outlet property="linkButton" destination="5Po-6e-k14" id="OoP-zB-985"/> <outlet property="linkButton" destination="5Po-6e-k14" id="qN6-zI-dIS"/>
<outlet property="passwordLabel" destination="9AD-b5-bun" id="Neh-tt-Ui8"/>
<outlet property="passwordTextField" destination="TH9-pF-YYq" id="vYS-Up-eeb"/>
<outlet property="pinInfoButton" destination="rtk-w4-zfQ" id="eo1-z8-7RN"/>
<outlet property="pinLabel" destination="VN2-rO-YYy" id="qaM-sZ-9hX"/>
<outlet property="pinTextField" destination="Cuu-Tq-miP" id="6Jk-h2-tyr"/>
</connections> </connections>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6ma-i4-SuK" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="6ma-i4-SuK" userLabel="First Responder" sceneMemberID="firstResponder"/>
......
...@@ -9,23 +9,108 @@ ...@@ -9,23 +9,108 @@
import UIKit import UIKit
import Reusable import Reusable
import RxSwift import RxSwift
import PKHUD
import AMPopTip
class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBased { class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBased {
// MARK: outlets // MARK: outlets
@IBOutlet weak var linkButton: DesignableButton! @IBOutlet weak var linkButton: DesignableButton!
@IBOutlet weak var pinTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var pinInfoButton: UIButton!
@IBOutlet weak var pinLabel: UILabel!
@IBOutlet weak var passwordLabel: UILabel!
// MARK: members // MARK: members
private let disposeBag = DisposeBag() private let disposeBag = DisposeBag()
var viewModel: LinkDeviceViewModel! var viewModel: LinkDeviceViewModel!
let popTip = PopTip()
// MARK: functions // MARK: functions
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
self.applyL10n()
//bind view model to view
self.pinInfoButton.rx.tap.subscribe(onNext: { [unowned self] (_) in
self.showPinInfo()
}).disposed(by: self.disposeBag)
self.linkButton.rx.tap.subscribe(onNext: { [unowned self] (_) in self.linkButton.rx.tap.subscribe(onNext: { [unowned self] (_) in
self.viewModel.linkDevice() self.viewModel.linkDevice()
}).disposed(by: self.disposeBag) }).disposed(by: self.disposeBag)
// handle linking state
self.viewModel.createState
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] (state) in
switch state {
case .started:
self?.showCreationHUD()
case .success:
self?.hideHud()
self?.showLinkedSuccess()
case .error (let error):
self?.hideHud()
self?.showAccountCreationError(error: error)
default:
self?.hideHud()
}
}, onError: { [weak self] (error) in
self?.hideHud()
if let error = error as? AccountCreationError {
self?.showAccountCreationError(error: error)
}
}).disposed(by: self.disposeBag)
self.viewModel.linkButtonEnabledState.bind(to: self.linkButton.rx.isEnabled)
.disposed(by: self.disposeBag)
// bind view to view model
self.pinTextField.rx.text.orEmpty.bind(to: self.viewModel.pin).disposed(by: self.disposeBag)
self.passwordTextField.rx.text.orEmpty.bind(to: self.viewModel.password).disposed(by: self.disposeBag)
} }
private func applyL10n() {
self.linkButton.setTitle(L10n.Linktoaccount.linkButtonTitle, for: .normal)
self.pinLabel.text = L10n.Linktoaccount.pinLabel
self.passwordLabel.text = L10n.Linktoaccount.passwordLabel
self.pinTextField.placeholder = L10n.Linktoaccount.pinPlaceholder
self.passwordTextField.placeholder = L10n.Linktoaccount.passwordPlaceholder
}
private func showCreationHUD() {
HUD.show(.labeledProgress(title: L10n.Linktoaccount.waitLinkToAccountTitle, subtitle: nil))
}