Commit 2ff3a26a authored by Quentin Muret's avatar Quentin Muret Committed by Kateryna Kostiuk

UI/UX: refactor welcome and account creation view

- refactor UI / UX
- New launchScreen
- add enable notification switch (on by default)
- add encrypt my local account switch (off by default)
- manage correctly the bottom offset of the scroll view (when
  the keyboard is shown or dismissed)
- we can now dismiss the keyboard when tipping outside and
  scroll it manually
- adapt the UI for all devices
- the UI texts are now changing dynamically regarding the
  language of the device

Change-Id: I4fecb7bc5bfda5585ce7a4c83ad3a64a2e6b246c
Reviewed-by: Kateryna Kostiuk<kateryna.kostiuk@savoirfairelinux.com>
parent 67c37f47
......@@ -9,5 +9,5 @@ github "ashleymills/Reachability.swift" "v4.3.0"
github "gskbyte/GSKStretchyHeaderView" "1.0.4"
github "optonaut/ActiveLabel.swift" "1.0.1"
github "pkluz/PKHUD" "5.2.0"
github "realm/realm-cocoa" "v3.11.1"
github "realm/realm-cocoa" "v3.12.0"
github "stephencelis/SQLite.swift" "0.11.5"
......@@ -40,6 +40,7 @@ internal enum Asset {
internal static let enableSpeakerphone = ImageAsset(name: "enable_speakerphone")
internal static let fallbackAvatar = ImageAsset(name: "fallback_avatar")
internal static let icContactPicture = ImageAsset(name: "ic_contact_picture")
internal static let jamiIcon = ImageAsset(name: "jamiIcon")
internal static let leftArrow = ImageAsset(name: "left_arrow")
internal static let moreSettings = ImageAsset(name: "more_settings")
internal static let pauseCall = ImageAsset(name: "pause_call")
......
......@@ -128,25 +128,35 @@ internal enum L10n {
}
internal enum CreateAccount {
/// Encrypt my account
internal static let chooseAPassword = L10n.tr("Localizable", "createAccount.ChooseAPassword")
/// Choose strong password you will remember to protect your Ring account.
internal static let chooseStrongPassword = L10n.tr("Localizable", "createAccount.chooseStrongPassword")
/// Create your Ring account
/// Create your account
internal static let createAccountFormTitle = L10n.tr("Localizable", "createAccount.createAccountFormTitle")
/// username
/// Notifications
internal static let enableNotifications = L10n.tr("Localizable", "createAccount.EnableNotifications")
/// Username
internal static let enterNewUsernamePlaceholder = L10n.tr("Localizable", "createAccount.enterNewUsernamePlaceholder")
/// invalid username
internal static let invalidUsername = L10n.tr("Localizable", "createAccount.invalidUsername")
/// Loading
internal static let loading = L10n.tr("Localizable", "createAccount.loading")
/// looking for username availability
/// looking for availability…
internal static let lookingForUsernameAvailability = L10n.tr("Localizable", "createAccount.lookingForUsernameAvailability")
/// password
/// Password
internal static let newPasswordPlaceholder = L10n.tr("Localizable", "createAccount.newPasswordPlaceholder")
/// 6 characters minimum
internal static let passwordCharactersNumberError = L10n.tr("Localizable", "createAccount.passwordCharactersNumberError")
/// Choose a password to encrypt your local account. Don’t forget it or you will not be able to recover your account
internal static let passwordInformation = L10n.tr("Localizable", "createAccount.PasswordInformation")
/// passwords do not match
internal static let passwordNotMatchingError = L10n.tr("Localizable", "createAccount.passwordNotMatchingError")
/// confirm password
/// (Recommended)
internal static let recommended = L10n.tr("Localizable", "createAccount.Recommended")
/// Register a username
internal static let registerAUsername = L10n.tr("Localizable", "createAccount.RegisterAUsername")
/// Confirm password
internal static let repeatPasswordPlaceholder = L10n.tr("Localizable", "createAccount.repeatPasswordPlaceholder")
/// username already taken
internal static let usernameAlreadyTaken = L10n.tr("Localizable", "createAccount.usernameAlreadyTaken")
......@@ -250,13 +260,13 @@ internal enum L10n {
}
internal enum Welcome {
/// Create a Ring account
/// Create a Jami account
internal static let createAccount = L10n.tr("Localizable", "welcome.createAccount")
/// Link this device to an account
internal static let linkDevice = L10n.tr("Localizable", "welcome.linkDevice")
/// Ring is a free and universal communication platform which preserves the users' privacy and freedoms
internal static let text = L10n.tr("Localizable", "welcome.text")
/// Welcome to Ring
/// Welcome to Jami !
internal static let title = L10n.tr("Localizable", "welcome.title")
}
}
......
......@@ -34,8 +34,8 @@ extension UIColor {
self.init(red: (hex >> 16) & 0xff, green: (hex >> 8) & 0xff, blue: hex & 0xff, alpha: alpha)
}
static let ringMain = UIColor(red: 54, green: 125, blue: 156, alpha: 1.0)
static let ringSecondary = UIColor(red: 0, green: 76, blue: 96, alpha: 1.0)
static let ringMain = UIColor(hex: 0x017CBD, alpha: 1.0) // jami style
static let ringSecondary = UIColor(hex: 0x1F4971, alpha: 1.0) // jami style
static let ringMainLight = UIColor(red: 0, green: 76, blue: 96, alpha: 1.0)
static let ringMsgCellEmoji = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
static let ringMsgCellSent = UIColor(red: 58, green: 192, blue: 210, alpha: 1.0)
......@@ -52,4 +52,7 @@ extension UIColor {
static let ringSuccess = UIColor(hex: 0x00b20b, alpha: 1.0)
static let ringFailure = UIColor(hex: 0xf00000, alpha: 1.0)
static let ringWarning = UIColor.orange
static let jamiButtonLight = UIColor(hex: 0x285F97, alpha: 1.0)
static let jamiButtonDark = UIColor(hex: 0x0F2643, alpha: 1.0)
}
......@@ -151,4 +151,51 @@ extension UIView {
UIGraphicsEndImageContext()
return image
}
func applyGradient(with colours: [UIColor], locations: [NSNumber]? = nil) {
let gradient = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, at: 0)
}
func applyGradient(with colours: [UIColor], gradient orientation: GradientOrientation) {
let gradient = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.startPoint = orientation.startPoint
gradient.endPoint = orientation.endPoint
self.layer.insertSublayer(gradient, at: 0)
}
}
typealias GradientPoints = (startPoint: CGPoint, endPoint: CGPoint)
enum GradientOrientation {
case topRightBottomLeft
case topLeftBottomRight
case horizontal
case vertical
var startPoint : CGPoint {
return points.startPoint
}
var endPoint : CGPoint {
return points.endPoint
}
var points : GradientPoints {
switch self {
case .topRightBottomLeft:
return (CGPoint(x: 0.0,y: 1.0), CGPoint(x: 1.0,y: 0.0))
case .topLeftBottomRight:
return (CGPoint(x: 0.0,y: 0.0), CGPoint(x: 1,y: 1))
case .horizontal:
return (CGPoint(x: 0.0,y: 0.5), CGPoint(x: 1.0,y: 0.5))
case .vertical:
return (CGPoint(x: 0.0,y: 0.0), CGPoint(x: 0.0,y: 1.0))
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="COY-AX-993">
<device id="retina4_7" orientation="portrait">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="COY-AX-993">
<device id="retina5_9" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
......@@ -19,56 +18,23 @@
<viewControllerLayoutGuide type="bottom" id="yiq-Ru-NtI"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="aRx-1z-bhh">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="RING" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mT3-yy-Ins">
<rect key="frame" x="162" y="320.5" width="51" height="26.5"/>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="background_ring" translatesAutoresizingMaskIntoConstraints="NO" id="0jH-Qw-sbt">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vx3-sT-ceQ" userLabel="Gradient View">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" verticalHuggingPriority="251" image="ring_logo" translatesAutoresizingMaskIntoConstraints="NO" id="noP-kw-7tM">
<rect key="frame" x="92" y="302" width="191" height="63"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</imageView>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="T5f-Vn-hsM">
<rect key="frame" x="169.5" y="373" width="37" height="37"/>
<constraints>
<constraint firstAttribute="height" constant="37" id="OXD-aw-oL2"/>
<constraint firstAttribute="width" constant="37" id="W9J-rm-eGu"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="0.2274509804" green="0.75294117650000003" blue="0.82352941180000006" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="displayP3"/>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" verticalHuggingPriority="251" image="jamiIcon" translatesAutoresizingMaskIntoConstraints="NO" id="noP-kw-7tM">
<rect key="frame" x="137.66666666666666" y="358.66666666666669" width="100" height="95"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="T5f-Vn-hsM" firstAttribute="top" secondItem="noP-kw-7tM" secondAttribute="bottom" constant="8" id="9DO-PZ-5no"/>
<constraint firstItem="T5f-Vn-hsM" firstAttribute="centerX" secondItem="vx3-sT-ceQ" secondAttribute="centerX" id="LBl-Ca-4f2"/>
<constraint firstItem="noP-kw-7tM" firstAttribute="centerY" secondItem="vx3-sT-ceQ" secondAttribute="centerY" id="OjY-lE-ODE"/>
<constraint firstItem="noP-kw-7tM" firstAttribute="centerX" secondItem="vx3-sT-ceQ" secondAttribute="centerX" id="q4D-DQ-coq"/>
<constraint firstAttribute="width" secondItem="noP-kw-7tM" secondAttribute="height" multiplier="20:19" id="90r-Az-47a"/>
<constraint firstAttribute="width" constant="100" id="u8R-gO-yAc"/>
</constraints>
</view>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="0jH-Qw-sbt" firstAttribute="leading" secondItem="aRx-1z-bhh" secondAttribute="leading" id="7DO-cX-ZHu"/>
<constraint firstAttribute="bottom" secondItem="vx3-sT-ceQ" secondAttribute="bottom" id="Dbq-On-bgN"/>
<constraint firstItem="mT3-yy-Ins" firstAttribute="centerX" secondItem="aRx-1z-bhh" secondAttribute="centerX" id="TUh-hS-ILM"/>
<constraint firstItem="0jH-Qw-sbt" firstAttribute="top" secondItem="aRx-1z-bhh" secondAttribute="top" id="Ttd-hs-cxC"/>
<constraint firstAttribute="trailing" secondItem="0jH-Qw-sbt" secondAttribute="trailing" id="bQI-fo-zjq"/>
<constraint firstItem="mT3-yy-Ins" firstAttribute="centerY" secondItem="aRx-1z-bhh" secondAttribute="centerY" id="hcy-ws-hgV"/>
<constraint firstAttribute="trailing" secondItem="vx3-sT-ceQ" secondAttribute="trailing" id="iio-7B-a2J"/>
<constraint firstItem="vx3-sT-ceQ" firstAttribute="top" secondItem="aRx-1z-bhh" secondAttribute="top" id="ltY-hm-fnP"/>
<constraint firstItem="yiq-Ru-NtI" firstAttribute="top" secondItem="0jH-Qw-sbt" secondAttribute="bottom" id="vPl-N3-Vvw"/>
<constraint firstItem="vx3-sT-ceQ" firstAttribute="leading" secondItem="aRx-1z-bhh" secondAttribute="leading" id="yoR-WM-6bH"/>
<constraint firstItem="noP-kw-7tM" firstAttribute="centerY" secondItem="aRx-1z-bhh" secondAttribute="centerY" id="YcT-vx-Xtv"/>
<constraint firstItem="noP-kw-7tM" firstAttribute="centerX" secondItem="aRx-1z-bhh" secondAttribute="centerX" id="gPC-Oy-B1H"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vc6-gh-ZiE"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="u5I-td-CmB" userLabel="First Responder" sceneMemberID="firstResponder"/>
......@@ -77,7 +43,6 @@
</scene>
</scenes>
<resources>
<image name="background_ring" width="750" height="1334"/>
<image name="ring_logo" width="191" height="63"/>
<image name="jamiIcon" width="200" height="190"/>
</resources>
</document>
......@@ -33,27 +33,49 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
self.registerUsernameHeightConstraintConstant = registerUsernameHeightConstraint.constant
}
}
@IBOutlet weak var backgroundNavigationBarHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var choosePasswordViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var scrollViewBottomConstraint: NSLayoutConstraint!
@IBOutlet weak var usernameSwitch: UISwitch!
@IBOutlet weak var passwordSwitch: UISwitch!
@IBOutlet weak var notificationsSwitch: UISwitch!
@IBOutlet weak var registerUsernameView: UIView!
@IBOutlet weak var registerPasswordView: UIView!
@IBOutlet weak var registerUsernameLabel: UILabel!
@IBOutlet weak var recommendedLabel: UILabel!
@IBOutlet weak var registerUsernameErrorLabel: UILabel!
@IBOutlet weak var passwordTextField: DesignableTextField!
@IBOutlet weak var confirmPasswordTextField: DesignableTextField!
@IBOutlet weak var passwordErrorLabel: UILabel!
@IBOutlet weak var usernameTextField: DesignableTextField!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var chooseAPasswordLabel: UILabel!
@IBOutlet weak var passwordInfoLabel: UILabel!
@IBOutlet weak var enableNotificationsLabel: UILabel!
// MARK: members
private let disposeBag = DisposeBag()
var viewModel: CreateAccountViewModel!
var registerUsernameHeightConstraintConstant: CGFloat = 0.0
@IBOutlet weak var containerViewBottomConstraint: NSLayoutConstraint!
var keyboardDismissTapRecognizer: UITapGestureRecognizer!
var isKeyboardOpened: Bool = false
// MARK: functions
override func viewDidLoad() {
super.viewDidLoad()
// L10n
self.applyL10n()
super.viewDidLoad()
self.view.layoutIfNeeded()
// Style
self.scrollView.alwaysBounceHorizontal = false
self.scrollView.alwaysBounceVertical = true
self.createAccountButton.applyGradient(with: [UIColor.jamiButtonLight, UIColor.jamiButtonDark], gradient: .horizontal)
let device = UIDevice.modelName
self.backgroundNavigationBarHeightConstraint.constant = UIApplication.shared.statusBarFrame.height
self.usernameTextField.tintColor = UIColor.ringSecondary
self.passwordTextField.tintColor = UIColor.ringSecondary
self.confirmPasswordTextField.tintColor = UIColor.ringSecondary
// Bind ViewModel to View
self.bindViewModelToView()
......@@ -63,11 +85,55 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
// handle keyboard
self.adaptToKeyboardState(for: self.scrollView, with: self.disposeBag)
keyboardDismissTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIApplication.shared.statusBarStyle = .default
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(withNotification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(withNotification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func setContentInset() {
if !self.isKeyboardOpened {
self.containerViewBottomConstraint.constant = -20
return
}
let device = UIDevice.modelName
switch device {
case "iPhone X", "iPhone XS", "iPhone XS Max", "iPhone XR" :
self.containerViewBottomConstraint.constant = 100
default :
self.containerViewBottomConstraint.constant = 70
}
}
@objc func dismissKeyboard() {
self.isKeyboardOpened = false
self.becomeFirstResponder()
view.removeGestureRecognizer(keyboardDismissTapRecognizer)
}
@objc func keyboardWillAppear(withNotification: NSNotification){
self.isKeyboardOpened = true
self.view.addGestureRecognizer(keyboardDismissTapRecognizer)
self.setContentInset()
}
@objc func keyboardWillDisappear(withNotification: NSNotification){
view.removeGestureRecognizer(keyboardDismissTapRecognizer)
self.setContentInset()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
override var canBecomeFirstResponder: Bool {
return true
}
private func applyL10n() {
......@@ -76,6 +142,11 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
self.usernameTextField.placeholder = self.viewModel.usernameTitle
self.passwordTextField.placeholder = self.viewModel.passwordTitle
self.confirmPasswordTextField.placeholder = self.viewModel.confirmPasswordTitle
self.registerUsernameLabel.text = self.viewModel.registerAUserNameTitle
self.chooseAPasswordLabel.text = self.viewModel.chooseAPasswordTitle
self.passwordInfoLabel.text = self.viewModel.passwordInfoTitle
self.enableNotificationsLabel.text = self.viewModel.enableNotificationsTitle
self.recommendedLabel.text = self.viewModel.recommendedTitle
}
private func bindViewModelToView() {
......@@ -86,18 +157,37 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
UIView.animate(withDuration: 0.3, animations: {
if isOn {
self.registerUsernameHeightConstraint.constant = self.registerUsernameHeightConstraintConstant
self.registerUsernameView.alpha = 1.0
DispatchQueue.global(qos: .background).async {
usleep(300000)
DispatchQueue.main.async {
UIView.animate(withDuration: 0.3, animations: {
self.registerUsernameView.alpha = 1.0
})
}
}
} else {
self.registerUsernameHeightConstraint.constant = 0
self.registerUsernameView.alpha = 0.0
}
self.setContentInset()
self.view.layoutIfNeeded()
})
}).disposed(by: self.disposeBag)
// handle Create Account Button state
self.viewModel.canAskForAccountCreation.bind(to: self.createAccountButton.rx.isEnabled).disposed(by: self.disposeBag)
self.viewModel.canAskForAccountCreation.subscribe(onNext: { [weak self] enable in
if enable {
DispatchQueue.main.async {
self?.createAccountButton.alpha = 1
self?.createAccountButton.isEnabled = true
}
} else {
DispatchQueue.main.async {
self?.createAccountButton.alpha = 0.6
self?.createAccountButton.isEnabled = false
}
}
}).disposed(by: self.disposeBag)
// handle password error
self.viewModel.passwordValidationState.map { $0.isValidated }
......@@ -136,9 +226,40 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
}).disposed(by: self.disposeBag)
}
private func managePasswordSwitch(isOn: Bool) {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
if isOn {
guard let height = self?.passwordInfoLabel.frame.height else {return}
self?.registerPasswordView.isHidden = false
self?.choosePasswordViewHeightConstraint.constant = 133 + height
self?.view.layoutIfNeeded()
DispatchQueue.global(qos: .background).async {
usleep(300000)
DispatchQueue.main.async {
UIView.animate(withDuration: 0.3, animations: {
self?.registerPasswordView.alpha = 1.0
})
}
}
} else {
self?.choosePasswordViewHeightConstraint.constant = 0
self?.registerPasswordView.alpha = 0.0
self?.passwordTextField.text = ""
self?.confirmPasswordTextField.text = ""
self?.passwordErrorLabel.isHidden = true
}
self?.setContentInset()
self?.view.layoutIfNeeded()
})
}
private func bindViewToViewModel() {
// Bind View Outlets to ViewModel
self.usernameSwitch.rx.isOn.bind(to: self.viewModel.registerUsername).disposed(by: self.disposeBag)
self.passwordSwitch.rx.isOn.subscribe(onNext: { [weak self] isOn in
self?.managePasswordSwitch(isOn: isOn)
}).disposed(by: self.disposeBag)
self.notificationsSwitch.rx.isOn.bind(to: self.viewModel.notificationSwitch).disposed(by: self.disposeBag)
self.usernameTextField.rx.text.orEmpty.throttle(3, scheduler: MainScheduler.instance).distinctUntilChanged().bind(to: self.viewModel.username).disposed(by: self.disposeBag)
self.passwordTextField.rx.text.orEmpty.bind(to: self.viewModel.password).disposed(by: self.disposeBag)
self.confirmPasswordTextField.rx.text.orEmpty.bind(to: self.viewModel.confirmPassword).disposed(by: self.disposeBag)
......
......@@ -153,6 +153,11 @@ class CreateAccountViewModel: Stateable, ViewModel {
let usernameTitle = L10n.CreateAccount.enterNewUsernamePlaceholder
let passwordTitle = L10n.CreateAccount.newPasswordPlaceholder
let confirmPasswordTitle = L10n.CreateAccount.repeatPasswordPlaceholder
let registerAUserNameTitle = L10n.CreateAccount.registerAUsername
let chooseAPasswordTitle = L10n.CreateAccount.chooseAPassword
let passwordInfoTitle = L10n.CreateAccount.passwordInformation
let enableNotificationsTitle = L10n.CreateAccount.enableNotifications
let recommendedTitle = L10n.CreateAccount.recommended
// MARK: - Low level services
private let accountService: AccountsService
......@@ -167,6 +172,7 @@ class CreateAccountViewModel: Stateable, ViewModel {
let password = Variable<String>("")
let confirmPassword = Variable<String>("")
let registerUsername = Variable<Bool>(true)
let notificationSwitch = Variable<Bool>(true)
lazy var passwordValidationState: Observable<PasswordValidationState> = {
return Observable.combineLatest(self.password.asObservable(), self.confirmPassword.asObservable())
{ (password: String, confirmPassword: String) -> PasswordValidationState in
......@@ -281,6 +287,15 @@ class CreateAccountViewModel: Stateable, ViewModel {
func createAccount() {
self.accountCreationState.value = .started
self.accountService.addRingAccount(withUsername: self.username.value,
password: self.password.value)
password: self.password.value, enable: self.notificationSwitch.value)
self.enablePushNotifications(enable: self.notificationSwitch.value)
}
func enablePushNotifications(enable: Bool) {
if enable {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: NotificationName.enablePushNotifications.rawValue), object: nil)
return
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: NotificationName.disablePushNotifications.rawValue), object: nil)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ILs-xb-iKr">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ILs-xb-iKr">
<device id="retina5_9" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......@@ -19,61 +18,41 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="background_ring" translatesAutoresizingMaskIntoConstraints="NO" id="11r-JK-mPT">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8TU-za-C7U" userLabel="Gradient View" customClass="DesignableView" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<color key="backgroundColor" red="0.2274509804" green="0.75294117650000003" blue="0.82352941180000006" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="displayP3"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="gradientStartColor">
<color key="value" red="0.2274509804" green="0.75294117650000003" blue="0.82352941180000006" alpha="0.0" colorSpace="custom" customColorSpace="displayP3"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="gradientEndColor">
<color key="value" red="0.2274509804" green="0.75294117650000003" blue="0.82352941180000006" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" verticalHuggingPriority="251" image="ring_logo" translatesAutoresizingMaskIntoConstraints="NO" id="2Pc-uJ-SAI">
<rect key="frame" x="92" y="301.66666666666669" width="191" height="70"/>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" verticalHuggingPriority="251" image="jamiIcon" translatesAutoresizingMaskIntoConstraints="NO" id="2Pc-uJ-SAI">
<rect key="frame" x="137.66666666666666" y="358.66666666666669" width="100" height="95"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" secondItem="2Pc-uJ-SAI" secondAttribute="height" multiplier="30:11" id="Qre-jC-ga0"/>
<constraint firstAttribute="width" secondItem="2Pc-uJ-SAI" secondAttribute="height" multiplier="20:19" id="5fN-uH-uSi"/>
<constraint firstAttribute="width" constant="100" id="TaY-2a-CCG"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Ring is a free and universal communication platform which preserves the users' privacy and freedoms" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E4b-Zv-unB">
<rect key="frame" x="62.666666666666657" y="428.33333333333331" width="249.99999999999997" height="46.666666666666686"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Live Free or Die" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lbn-cd-UXk" userLabel="Version Title Label">
<rect key="frame" x="108.33333333333333" y="391.66666666666669" width="159.33333333333337" height="28.666666666666686"/>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.0" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Welcome to jami !" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E4b-Zv-unB">
<rect key="frame" x="59" y="483.66666666666669" width="257.33333333333331" height="43.000000000000057"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QLK-gs-fOJ" customClass="DesignableButton" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="62.666666666666657" y="575" width="249.99999999999997" height="40"/>
<color key="backgroundColor" red="0.0" green="0.29803921570000003" blue="0.37647058820000001" alpha="1" colorSpace="calibratedRGB"/>
<button opaque="NO" alpha="0.0" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bu0-90-MB5" customClass="DesignableButton" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="37.666666666666657" y="566.66666666666663" width="300" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="YW4-Sc-61P"/>
<constraint firstAttribute="height" constant="50" id="FEf-kf-jCs"/>
<constraint firstAttribute="width" constant="300" id="epE-7u-SMQ"/>
</constraints>
<state key="normal" title="Link this device to an account">
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="18"/>
<state key="normal" title="Create a Ring account">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
</userDefinedRuntimeAttributes>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bu0-90-MB5" customClass="DesignableButton" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="62.666666666666657" y="515" width="249.99999999999997" height="40"/>
<color key="backgroundColor" red="0.0" green="0.29803921570000003" blue="0.37647058820000001" alpha="1" colorSpace="calibratedRGB"/>
<button opaque="NO" alpha="0.0" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QLK-gs-fOJ" customClass="DesignableButton" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="37.666666666666657" y="636.66666666666663" width="300" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="FEf-kf-jCs"/>
<constraint firstAttribute="width" constant="250" id="epE-7u-SMQ"/>
<constraint firstAttribute="height" constant="50" id="YW4-Sc-61P"/>