Commit 74b6fec4 authored by Quentin Muret's avatar Quentin Muret Committed by Kateryna Kostiuk

UI / UX: refactor link device view

- refactor UI / UX
- 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
- reduce the wide of the forms on iPad of link device,
  create account and welcome pages
- the PIN text field is autofocus automatically when opening
  the page

Change-Id: I54bd673f3a066b37d8cdf249d7451e3584b28b8f
parent 2ff3a26a
......@@ -225,7 +225,7 @@ internal enum L10n {
internal static let linkButtonTitle = L10n.tr("Localizable", "linkToAccount.linkButtonTitle")
/// Enter Password
internal static let passwordLabel = L10n.tr("Localizable", "linkToAccount.passwordLabel")
/// password
/// Password
internal static let passwordPlaceholder = L10n.tr("Localizable", "linkToAccount.passwordPlaceholder")
/// Enter PIN
internal static let pinLabel = L10n.tr("Localizable", "linkToAccount.pinLabel")
......
......@@ -73,6 +73,7 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
self.createAccountButton.applyGradient(with: [UIColor.jamiButtonLight, UIColor.jamiButtonDark], gradient: .horizontal)
let device = UIDevice.modelName
self.backgroundNavigationBarHeightConstraint.constant = UIApplication.shared.statusBarFrame.height
self.usernameTextField.becomeFirstResponder()
self.usernameTextField.tintColor = UIColor.ringSecondary
self.passwordTextField.tintColor = UIColor.ringSecondary
self.confirmPasswordTextField.tintColor = UIColor.ringSecondary
......@@ -174,20 +175,8 @@ class CreateAccountViewController: UIViewController, StoryboardBased, ViewModelB
})
}).disposed(by: self.disposeBag)
// handle Create Account Button state
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)
self.viewModel.canAskForAccountCreation.bind(to: self.createAccountButton.rx.isEnabled)
.disposed(by: self.disposeBag)
// handle password error
self.viewModel.passwordValidationState.map { $0.isValidated }
......
......@@ -16,7 +16,10 @@ import SwiftyBeaver
class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBased {
// MARK: outlets
@IBOutlet weak var linkDeviceTitle: UILabel!
@IBOutlet weak var linkButton: DesignableButton!
@IBOutlet weak var backgroundNavigationBarHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var containerViewBottomConstraint: NSLayoutConstraint!
@IBOutlet weak var pinTextField: DesignableTextField!
@IBOutlet weak var passwordTextField: DesignableTextField!
@IBOutlet weak var pinInfoButton: UIButton!
......@@ -26,6 +29,8 @@ class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBase
// MARK: members
private let disposeBag = DisposeBag()
var viewModel: LinkDeviceViewModel!
var keyboardDismissTapRecognizer: UITapGestureRecognizer!
var isKeyboardOpened: Bool = false
let popTip = PopTip()
let log = SwiftyBeaver.self
......@@ -34,6 +39,14 @@ class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBase
override func viewDidLoad() {
super.viewDidLoad()
// Style
self.pinTextField.becomeFirstResponder()
self.view.layoutIfNeeded()
self.linkButton.applyGradient(with: [UIColor.jamiButtonLight, UIColor.jamiButtonDark], gradient: .horizontal)
self.backgroundNavigationBarHeightConstraint.constant = UIApplication.shared.statusBarFrame.height
self.pinTextField.tintColor = UIColor.ringSecondary
self.passwordTextField.tintColor = UIColor.ringSecondary
self.applyL10n()
//bind view model to view
......@@ -75,11 +88,53 @@ class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBase
// 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)
// handle keyboard
self.adaptToKeyboardState(for: self.scrollView, with: self.disposeBag)
keyboardDismissTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
}
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 = -40
default :
self.containerViewBottomConstraint.constant = -65
}
}
@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 var canBecomeFirstResponder: Bool {
return true
}
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)
}
private func applyL10n() {
......@@ -88,6 +143,7 @@ class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBase
self.passwordLabel.text = L10n.LinkToAccount.passwordLabel
self.pinTextField.placeholder = L10n.LinkToAccount.pinPlaceholder
self.passwordTextField.placeholder = L10n.LinkToAccount.passwordPlaceholder
self.linkDeviceTitle.text = L10n.LinkToAccount.linkButtonTitle
}
private func showCreationHUD() {
......@@ -118,10 +174,10 @@ class LinkDeviceViewController: UIViewController, StoryboardBased, ViewModelBase
popTip.entranceAnimation = .scale
popTip.bubbleColor = UIColor.ringSecondary
popTip.textColor = UIColor.white
let offset: CGFloat = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad) ? 60.0 : 80.0
let offset: CGFloat = 20.0
popTip.offset = offset - scrollView.contentOffset.y
popTip.show(text: L10n.LinkToAccount.explanationPinMessage, direction: .down,
maxWidth: 250, in: self.view, from: pinInfoButton.frame)
maxWidth: 255, in: self.view, from: pinInfoButton.frame)
}
}
}
......@@ -33,10 +33,10 @@
<nil key="highlightedColor"/>
</label>
<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"/>
<rect key="frame" x="40" y="566.66666666666663" width="295" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="FEf-kf-jCs"/>
<constraint firstAttribute="width" constant="300" id="epE-7u-SMQ"/>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="epE-7u-SMQ"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="18"/>
<state key="normal" title="Create a Ring account">
......@@ -47,7 +47,7 @@
</userDefinedRuntimeAttributes>
</button>
<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"/>
<rect key="frame" x="40" y="636.66666666666663" width="295" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="YW4-Sc-61P"/>
</constraints>
......@@ -65,6 +65,7 @@
<constraint firstItem="bu0-90-MB5" firstAttribute="top" secondItem="E4b-Zv-unB" secondAttribute="bottom" constant="40" id="0hJ-6T-D3J"/>
<constraint firstItem="2Pc-uJ-SAI" firstAttribute="centerY" secondItem="Dg0-kS-rT7" secondAttribute="centerY" id="2w4-nZ-VwS"/>
<constraint firstItem="E4b-Zv-unB" firstAttribute="top" secondItem="2Pc-uJ-SAI" secondAttribute="bottom" constant="30" id="99p-KU-QhW"/>
<constraint firstItem="bu0-90-MB5" firstAttribute="leading" secondItem="hvJ-fJ-PMc" secondAttribute="leading" priority="750" constant="40" id="OTd-qD-as2"/>
<constraint firstItem="QLK-gs-fOJ" firstAttribute="leading" secondItem="bu0-90-MB5" secondAttribute="leading" id="U37-r7-lNe"/>
<constraint firstItem="bu0-90-MB5" firstAttribute="centerX" secondItem="Dg0-kS-rT7" secondAttribute="centerX" id="YLx-WX-rgL"/>
<constraint firstItem="QLK-gs-fOJ" firstAttribute="top" secondItem="bu0-90-MB5" secondAttribute="bottom" constant="20" id="cYv-WZ-CCB"/>
......@@ -72,6 +73,7 @@
<constraint firstItem="2Pc-uJ-SAI" firstAttribute="centerX" secondItem="Dg0-kS-rT7" secondAttribute="centerX" id="qaX-bX-RjJ"/>
<constraint firstItem="QLK-gs-fOJ" firstAttribute="trailing" secondItem="bu0-90-MB5" secondAttribute="trailing" id="uLc-95-Qpb"/>
<constraint firstItem="E4b-Zv-unB" firstAttribute="centerX" secondItem="Dg0-kS-rT7" secondAttribute="centerX" id="ukg-Rd-bL3"/>
<constraint firstItem="hvJ-fJ-PMc" firstAttribute="trailing" secondItem="bu0-90-MB5" secondAttribute="trailing" priority="750" constant="40" id="vGg-V2-7OH"/>
</constraints>
<viewLayoutGuide key="safeArea" id="hvJ-fJ-PMc"/>
</view>
......
......@@ -41,6 +41,7 @@ class WelcomeViewController: UIViewController, StoryboardBased, ViewModelBased {
// MARK: functions
override func viewDidLoad() {
super.viewDidLoad()
self.view.layoutIfNeeded()
self.initialAnimation()
self.createAccountButton.applyGradient(with: [UIColor.jamiButtonLight, UIColor.jamiButtonDark], gradient: .horizontal)
self.linkDeviceButton.applyGradient(with: [UIColor.jamiButtonLight, UIColor.jamiButtonDark], gradient: .horizontal)
......
......@@ -71,7 +71,7 @@
//Link To Account form
"linkToAccount.waitLinkToAccountTitle" = "Account linking";
"linkToAccount.linkButtonTitle" = "Link device";
"linkToAccount.passwordPlaceholder" = "password";
"linkToAccount.passwordPlaceholder" = "Password";
"linkToAccount.pinPlaceholder" = "PIN";
"linkToAccount.passwordLabel" = "Enter Password";
"linkToAccount.pinLabel" = "Enter PIN";
......
......@@ -70,12 +70,12 @@
//Link To Account form
"linkToAccount.waitLinkToAccountTitle" = "Account linking";
"linkToAccount.linkButtonTitle" = "Link device";
"linkToAccount.passwordPlaceholder" = "password";
"linkToAccount.pinPlaceholder" = "PIN";
"linkToAccount.passwordLabel" = "Enter Password";
"linkToAccount.pinLabel" = "Enter PIN";
"linkToAccount.explanationPinMessage" = "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.";
"linkToAccount.linkButtonTitle" = "Associer l'appareil";
"linkToAccount.passwordPlaceholder" = "Mot de passe";
"linkToAccount.pinPlaceholder" = "NIP";
"linkToAccount.passwordLabel" = "Entrez le mot de passe";
"linkToAccount.pinLabel" = "Entrer le NIP";
"linkToAccount.explanationPinMessage" = "Pour générer le code PIN, accédez aux paramètres de gestion de compte sur le périphérique contenant le compte que vous souhaitez utiliser. Dans la section \"appareils\", sélectionnez \"Lier un autre appareil à ce compte \". Vous obtiendrez le code PIN nécessaire pour remplir ce formulaire. Le code PIN n'est valide que 10 minutes.";
//Alerts
"alerts.accountCannotBeFoundTitle" = "Can't find account";
......
......@@ -71,12 +71,12 @@
//Link To Account form
"linkToAccount.waitLinkToAccountTitle" = "Account linking";
"linkToAccount.linkButtonTitle" = "Link device";
"linkToAccount.linkButtonTitle" = "Associer l'appareil";
"linkToAccount.passwordPlaceholder" = "Mot de passe";
"linkToAccount.pinPlaceholder" = "NIP";
"linkToAccount.passwordLabel" = "Enter Password";
"linkToAccount.passwordLabel" = "Entrez le mot de passe";
"linkToAccount.pinLabel" = "Entrer le NIP";
"linkToAccount.explanationPinMessage" = "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.";
"linkToAccount.explanationPinMessage" = "Pour générer le code PIN, accédez aux paramètres de gestion de compte sur le périphérique contenant le compte que vous souhaitez utiliser. Dans la section \"appareils\", sélectionnez \"Lier un autre appareil à ce compte \". Vous obtiendrez le code PIN nécessaire pour remplir ce formulaire. Le code PIN n'est valide que 10 minutes.";
//Alerts
"alerts.accountCannotBeFoundTitle" = "Impossible de trouver le compte";
......@@ -133,7 +133,7 @@
"accountPage.proxyDisabledAlertBody" = "In order to receive notifications, please enable proxy";
//Link New Device
"linkDevice.title" = "Link a new device";
"linkDevice.title" = "Associer cet appareil";
"linkDevice.passwordError" = "The password you entered does not unlock this account";
"linkDevice.networkError" = "Une erreur réseau s'est produite lors de l'exportation";
"linkDevice.defaultError" = "Une erreur s'est produite lors de l'exportation";
......
......@@ -70,12 +70,12 @@
//Link To Account form
"linkToAccount.waitLinkToAccountTitle" = "Account linking";
"linkToAccount.linkButtonTitle" = "Link device";
"linkToAccount.passwordPlaceholder" = "password";
"linkToAccount.pinPlaceholder" = "PIN";
"linkToAccount.passwordLabel" = "Enter Password";
"linkToAccount.pinLabel" = "Enter PIN";
"linkToAccount.explanationPinMessage" = "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.";
"linkToAccount.linkButtonTitle" = "Associer l'appareil";
"linkToAccount.passwordPlaceholder" = "Mot de passe";
"linkToAccount.pinPlaceholder" = "NIP";
"linkToAccount.passwordLabel" = "Entrez le mot de passe";
"linkToAccount.pinLabel" = "Entrer le NIP";
"linkToAccount.explanationPinMessage" = "Pour générer le code PIN, accédez aux paramètres de gestion de compte sur le périphérique contenant le compte que vous souhaitez utiliser. Dans la section \"appareils\", sélectionnez \"Lier un autre appareil à ce compte \". Vous obtiendrez le code PIN nécessaire pour remplir ce formulaire. Le code PIN n'est valide que 10 minutes.";
//Alerts
"alerts.accountCannotBeFoundTitle" = "Can't find account";
......
......@@ -70,12 +70,12 @@
//Link To Account form
"linkToAccount.waitLinkToAccountTitle" = "Account linking";
"linkToAccount.linkButtonTitle" = "Link device";
"linkToAccount.passwordPlaceholder" = "password";
"linkToAccount.pinPlaceholder" = "PIN";
"linkToAccount.passwordLabel" = "Enter Password";
"linkToAccount.pinLabel" = "Enter PIN";
"linkToAccount.explanationPinMessage" = "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.";
"linkToAccount.linkButtonTitle" = "Associer l'appareil";
"linkToAccount.passwordPlaceholder" = "Mot de passe";
"linkToAccount.pinPlaceholder" = "NIP";
"linkToAccount.passwordLabel" = "Entrez le mot de passe";
"linkToAccount.pinLabel" = "Entrer le NIP";
"linkToAccount.explanationPinMessage" = "Pour générer le code PIN, accédez aux paramètres de gestion de compte sur le périphérique contenant le compte que vous souhaitez utiliser. Dans la section \"appareils\", sélectionnez \"Lier un autre appareil à ce compte \". Vous obtiendrez le code PIN nécessaire pour remplir ce formulaire. Le code PIN n'est valide que 10 minutes.";
//Alerts
"alerts.accountCannotBeFoundTitle" = "Can't find account";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment