Commit d4cecfa8 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Andreas Traczyk

UI/UX: refactor account page

Change-Id: I65a20801615c8ca602e275d5e7b8f56dcf7c5b31
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 26f5b4ed
......@@ -117,6 +117,9 @@
0E3BD4362044B39F00A50DDF /* ProfileHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3BD4352044B39F00A50DDF /* ProfileHeaderView.swift */; };
0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */; };
0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */; };
0E438A96204F318200402900 /* AccountHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E438A95204F318200402900 /* AccountHeader.xib */; };
0E438A98204F31BD00402900 /* AccountHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E438A97204F31BD00402900 /* AccountHeader.swift */; };
0E438A9A204F47E700402900 /* SettingsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E438A99204F47E700402900 /* SettingsTableView.swift */; };
0E44B62F202B9DE40060F71B /* LocalNotificationsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */; };
0E48F9D31FDF150700D6CC08 /* GeneratedInteractionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F9D21FDF150700D6CC08 /* GeneratedInteractionsManager.swift */; };
0E4909611FE97A94005CAA50 /* ActiveLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E4909601FE97A94005CAA50 /* ActiveLabel.framework */; };
......@@ -405,6 +408,9 @@
0E3BD4352044B39F00A50DDF /* ProfileHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderView.swift; sourceTree = "<group>"; };
0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellGenerated.swift; sourceTree = "<group>"; };
0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellGenerated.xib; sourceTree = "<group>"; };
0E438A95204F318200402900 /* AccountHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountHeader.xib; sourceTree = "<group>"; };
0E438A97204F31BD00402900 /* AccountHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountHeader.swift; sourceTree = "<group>"; };
0E438A99204F47E700402900 /* SettingsTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableView.swift; sourceTree = "<group>"; };
0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationsHelper.swift; sourceTree = "<group>"; };
0E48F9D21FDF150700D6CC08 /* GeneratedInteractionsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedInteractionsManager.swift; sourceTree = "<group>"; };
0E4909601FE97A94005CAA50 /* ActiveLabel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ActiveLabel.framework; path = Carthage/Build/iOS/ActiveLabel.framework; sourceTree = "<group>"; };
......@@ -843,6 +849,7 @@
56AC650D1E85694D00EA1AA9 /* DesignableTextField.swift */,
1A2041901F1FD46200C08435 /* DesignableView.swift */,
0EB479941FA28A7300106AFD /* ButtonTransparentBackground.swift */,
0E438A99204F47E700402900 /* SettingsTableView.swift */,
);
path = UI;
sourceTree = "<group>";
......@@ -1317,6 +1324,8 @@
1A2D18EC1F2919D800B2C785 /* MeViewController.storyboard */,
1A5DC02B1F3565250075E8EF /* MeViewController.swift */,
1A2D18FE1F29352D00B2C785 /* MeViewModel.swift */,
0E438A95204F318200402900 /* AccountHeader.xib */,
0E438A97204F31BD00402900 /* AccountHeader.swift */,
);
path = Me;
sourceTree = "<group>";
......@@ -1634,6 +1643,7 @@
1A2D18B11F2915B600B2C785 /* SmartlistViewController.storyboard in Resources */,
0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */,
0E4909751FEAC943005CAA50 /* CallViewController.storyboard in Resources */,
0E438A96204F318200402900 /* AccountHeader.xib in Resources */,
04399A031D1C2D9D00E99CD9 /* Images.xcassets in Resources */,
1A2041841F1EA0FC00C08435 /* CreateAccountViewController.storyboard in Resources */,
0E2D5F551F9145F200D574BF /* LinkNewDeviceCell.xib in Resources */,
......@@ -1788,6 +1798,7 @@
02B22E091DF7585F000358C9 /* DaemonService.swift in Sources */,
5CE66F761FBF769B00EE9291 /* InitialLoadingViewController.swift in Sources */,
56BBC99F1ED714CB00CDAF8B /* MessagesAdapter.mm in Sources */,
0E438A9A204F47E700402900 /* SettingsTableView.swift in Sources */,
0E49096A1FEAB156005CAA50 /* CallsAdapter.mm in Sources */,
1A2D18A61F27F7A400B2C785 /* UIViewController+Rx.swift in Sources */,
0E7CF4DB20164B6700CD967D /* ButtonsContainerView.swift in Sources */,
......@@ -1869,6 +1880,7 @@
56BBC9DF1EDDC9D300CDAF8B /* LookupNameResponse.m in Sources */,
1A2041911F1FD46300C08435 /* DesignableView.swift in Sources */,
0ED2B6FE1F96A16C001572F0 /* LinkNewDeviceViewModel.swift in Sources */,
0E438A98204F31BD00402900 /* AccountHeader.swift in Sources */,
1A3D28A91F0EBF0200B524EE /* UIView+Ring.swift in Sources */,
1A2041881F1EA1EA00C08435 /* CreateAccountViewModel.swift in Sources */,
62E55B6D1F758E6F00D3FEF4 /* String+Helpers.swift in Sources */,
......
......@@ -11,6 +11,8 @@ enum L10n {
enum Accountpage {
/// Block List
static let blockedContacts = L10n.tr("Localizable", "accountPage.blockedContacts")
/// Account Details
static let credentialsHeader = L10n.tr("Localizable", "accountPage.credentialsHeader")
/// Devices
static let devicesListHeader = L10n.tr("Localizable", "accountPage.devicesListHeader")
/// Enable Push Notifications
......@@ -19,6 +21,10 @@ enum L10n {
static let settingsHeader = L10n.tr("Localizable", "accountPage.settingsHeader")
/// UNBLOCK
static let unblockContact = L10n.tr("Localizable", "accountPage.unblockContact")
/// username:
static let username = L10n.tr("Localizable", "accountPage.username")
/// username: not registered
static let usernameNotRegistered = L10n.tr("Localizable", "accountPage.usernameNotRegistered")
}
enum Actions {
......
......@@ -37,16 +37,19 @@ class EditProfileViewController: UIViewController, UITextFieldDelegate, UIImageP
override func viewDidLoad() {
super.viewDidLoad()
self.model = EditProfileViewModel()
self.setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setupUI()
UIApplication.shared.statusBarStyle = .lightContent
}
func setupUI() {
profileName.returnKeyType = .done
profileName.autocorrectionType = .no
self.model.image.asObservable()
.bind(to: self.profileImageView.rx.image)
.disposed(by: disposeBag)
......@@ -65,6 +68,10 @@ class EditProfileViewController: UIViewController, UITextFieldDelegate, UIImageP
}).disposed(by: disposeBag)
}
func resetProfileName() {
self.profileName.text = self.model.profileName.value
}
@objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
let alert = UIAlertController.init(title: nil,
......@@ -128,10 +135,4 @@ class EditProfileViewController: UIViewController, UITextFieldDelegate, UIImageP
profileImageView.image = image.circleMasked
dismiss(animated: true, completion: nil)
}
//hide keyboard when touch outside of text field
// override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// self.profileName.resignFirstResponder()
// self.profileName.text = self.model.profileName.value
// }
}
......@@ -58,10 +58,6 @@ class ConversationViewController: UIViewController, UITextFieldDelegate, Storybo
view.addGestureRecognizer(tap)
}
deinit {
print("conversationcontrollerdestroyed")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIApplication.shared.statusBarStyle = .default
......
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
*
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
class AccountHeader: GSKStretchyHeaderView {
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var profileName: UITextField!
override func didChangeStretchFactor(_ stretchFactor: CGFloat) {
var alpha = CGFloatTranslateRange(stretchFactor, 0.2, 0.7, 0, 1)
alpha = max(0, min(1, alpha))
self.profileImageView.alpha = alpha
self.profileName.alpha = alpha
var scale = CGFloatTranslateRange(stretchFactor, 0.1, 0.9, 0.6, 1)
scale = max(0.4, min(1, scale))
self.profileImageView.transform = CGAffineTransform(scaleX: scale, y: scale)
self.profileName.transform = CGAffineTransform(scaleX: scale, y: scale)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" 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"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="AccountHeader" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CHp-YH-dZ5">
<rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bD3-jT-xLr">
<rect key="frame" x="137" y="80" width="100" height="100"/>
<constraints>
<constraint firstAttribute="height" constant="100" id="2mb-uU-dHb"/>
<constraint firstAttribute="width" constant="100" id="WSb-4Z-9t2"/>
</constraints>
</imageView>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="name" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="oQJ-jT-wTv">
<rect key="frame" x="20" y="200" width="335" height="27"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<textInputTraits key="textInputTraits"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="NO"/>
</userDefinedRuntimeAttributes>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RQI-jN-lhc">
<rect key="frame" x="20" y="228" width="335" height="1"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="yUg-4a-h3g"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="RQI-jN-lhc" firstAttribute="top" secondItem="oQJ-jT-wTv" secondAttribute="bottom" constant="1" id="Pay-sK-Jbs"/>
<constraint firstItem="RQI-jN-lhc" firstAttribute="leading" secondItem="CHp-YH-dZ5" secondAttribute="leading" constant="20" id="an2-mQ-cD5"/>
<constraint firstItem="bD3-jT-xLr" firstAttribute="centerY" secondItem="CHp-YH-dZ5" secondAttribute="centerY" id="fk1-Ln-MyV"/>
<constraint firstAttribute="trailing" secondItem="RQI-jN-lhc" secondAttribute="trailing" constant="20" id="i5F-Y2-n1Y"/>
<constraint firstItem="oQJ-jT-wTv" firstAttribute="top" secondItem="bD3-jT-xLr" secondAttribute="bottom" constant="20" id="oKl-Yq-gZw"/>
<constraint firstItem="bD3-jT-xLr" firstAttribute="centerX" secondItem="CHp-YH-dZ5" secondAttribute="centerX" id="pf4-Dp-CPJ"/>
<constraint firstItem="oQJ-jT-wTv" firstAttribute="leading" secondItem="CHp-YH-dZ5" secondAttribute="leading" constant="20" id="txQ-DZ-CHU"/>
<constraint firstAttribute="trailing" secondItem="oQJ-jT-wTv" secondAttribute="trailing" constant="20" id="u0a-qO-EDQ"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="CHp-YH-dZ5" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="C9b-rk-lYC"/>
<constraint firstItem="CHp-YH-dZ5" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="XEI-v0-Cba"/>
<constraint firstItem="CHp-YH-dZ5" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="fPT-Ss-NTk"/>
<constraint firstItem="CHp-YH-dZ5" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="v1F-D0-1oe"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="maximumContentHeight">
<real key="value" value="260"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="profileImageView" destination="bD3-jT-xLr" id="wNj-F7-4yD"/>
<outlet property="profileName" destination="oQJ-jT-wTv" id="yaH-GU-Sih"/>
</connections>
<point key="canvasLocation" x="33.5" y="139"/>
</view>
</objects>
</document>
......@@ -29,14 +29,14 @@ class BlockListViewModel: ViewModel {
let disposeBag = DisposeBag()
lazy var blockedContactsItems: Observable<[BannedContactItem]> = {
return self.contacts.asObservable().map({ contacts in
return self.contacts.asObservable().map({ [weak self] contacts in
var bannedItems = [BannedContactItem]()
_ = contacts.filter {contact in contact.banned}
.map ({ contact in
let items = self.initialItems.filter({ item in
let items = self?.initialItems.filter({ item in
return item.contact.ringId == contact.ringId
})
if let first = items.first {
if let first = items?.first {
bannedItems.append(first)
}
})
......
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13174"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......@@ -20,23 +20,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Device ID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OQs-TS-z4j">
<rect key="frame" x="8" y="31.5" width="61.5" height="30"/>
<rect key="frame" x="16" y="32.5" width="61.5" height="26.5"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Emx-P1-xQc">
<rect key="frame" x="8" y="10" width="39.5" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nhJ-Qc-UCB">
<rect key="frame" x="15" y="77.5" width="345" height="1"/>
<color key="backgroundColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="PFf-5r-QZ9"/>
</constraints>
<rect key="frame" x="16" y="10" width="42" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
......@@ -45,10 +35,7 @@
<constraints>
<constraint firstItem="OQs-TS-z4j" firstAttribute="top" secondItem="Emx-P1-xQc" secondAttribute="bottom" constant="2" id="1u2-sP-E0H"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Emx-P1-xQc" secondAttribute="trailing" constant="20" symbolic="YES" id="3NP-Bl-2xN"/>
<constraint firstAttribute="bottom" secondItem="nhJ-Qc-UCB" secondAttribute="bottom" constant="1" id="J3B-DR-i7C"/>
<constraint firstItem="nhJ-Qc-UCB" firstAttribute="leading" secondItem="fvy-0B-phe" secondAttribute="leading" constant="15" id="QFw-mo-mRM"/>
<constraint firstItem="Emx-P1-xQc" firstAttribute="leading" secondItem="OQs-TS-z4j" secondAttribute="leading" id="VnE-T5-ZB0"/>
<constraint firstAttribute="trailing" secondItem="nhJ-Qc-UCB" secondAttribute="trailing" constant="15" id="XZz-Yv-j22"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="OQs-TS-z4j" secondAttribute="trailing" constant="10" id="c1v-0c-oUl"/>
<constraint firstItem="Emx-P1-xQc" firstAttribute="top" secondItem="fvy-0B-phe" secondAttribute="top" constant="10" id="jpW-b6-d6g"/>
<constraint firstItem="OQs-TS-z4j" firstAttribute="leading" secondItem="fvy-0B-phe" secondAttribute="leadingMargin" id="m5d-gg-Ugj"/>
......
......@@ -19,7 +19,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="contactAdd" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qQU-vB-ZuD" customClass="ButtonTransparentBackground" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="73.5" y="4.5" width="35" height="35"/>
<rect key="frame" x="65.5" y="4.5" width="35" height="35"/>
<constraints>
<constraint firstAttribute="width" constant="35" id="XIg-PF-p2r"/>
<constraint firstAttribute="height" constant="35" id="rZ3-3g-1AV"/>
......@@ -27,7 +27,8 @@
<color key="tintColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Gy-EN-BpG">
<rect key="frame" x="118.5" y="4.5" width="138" height="35"/>
<rect key="frame" x="110.5" y="4.5" width="154" height="35"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<state key="normal" title="Link Another Device">
<color key="titleColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</state>
......
......@@ -28,17 +28,17 @@ import RxDataSources
class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBased {
// MARK: - outlets
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ringIdLabel: UILabel!
@IBOutlet weak var settingsTable: UITableView!
@IBOutlet private weak var settingsTable: SettingsTableView!
// MARK: - members
var viewModel: MeViewModel!
fileprivate let disposeBag = DisposeBag()
private var stretchyHeader: AccountHeader!
// MARK: - functions
override func viewDidLoad() {
super.viewDidLoad()
self.addHeaderView()
self.navigationItem.title = L10n.Global.meTabBarTitle
self.configureBindings()
......@@ -50,15 +50,34 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
UIApplication.shared.statusBarStyle = .default
}
func configureBindings() {
self.viewModel.userName
.bind(to: self.nameLabel.rx.text)
.disposed(by: disposeBag)
private func addHeaderView() {
guard let nibViews = Bundle.main
.loadNibNamed("AccountHeader", owner: self, options: nil) else {
supportEditProfile()
return
}
guard let headerView = nibViews.first as? AccountHeader else {
supportEditProfile()
return
}
self.stretchyHeader = headerView
self.settingsTable.addSubview(self.stretchyHeader)
self.settingsTable.delegate = self
self.profileImageView = stretchyHeader.profileImageView
self.profileName = stretchyHeader.profileName
}
self.viewModel.ringId.asObservable()
.bind(to: self.ringIdLabel.rx.text)
.disposed(by: disposeBag)
private func supportEditProfile() {
// if loading grom nib failed add empty views requered by EditProfileViewController
let image = UIImageView()
let name = UITextField()
self.view.addSubview(image)
self.view.addSubview(name)
self.profileImageView = image
self.profileName = name
}
private func configureBindings() {
let infoButton = UIButton(type: .infoLight)
let infoItem = UIBarButtonItem(customView: infoButton)
infoButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
......@@ -72,7 +91,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
//setup Table
self.settingsTable.estimatedRowHeight = 50
self.settingsTable.rowHeight = UITableViewAutomaticDimension
self.settingsTable.separatorStyle = .none
self.settingsTable.tableFooterView = UIView()
//Register cell
self.setUpDataSource()
......@@ -82,7 +101,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
self.settingsTable.register(cellType: BlockContactsCell.self)
self.settingsTable.rx.itemSelected
.throttle(RxTimeInterval(2), scheduler: MainScheduler.instance)
//.throttle(RxTimeInterval(2), scheduler: MainScheduler.instance)
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] indexPath in
if (self?.settingsTable.cellForRow(at: indexPath) as? BlockContactsCell) != nil {
......@@ -92,11 +111,11 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
}).disposed(by: self.disposeBag)
}
func openBlockedList() {
private func openBlockedList() {
self.viewModel.showBlockedContacts()
}
func infoItemTapped() {
private func infoItemTapped() {
var compileDate: String {
let dateDefault = "20180131"
let dateFormatter = DateFormatter()
......@@ -121,7 +140,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
self.present(alert, animated: true, completion: nil)
}
func setUpDataSource() {
private func setUpDataSource() {
let configureCell: (TableViewSectionedDataSource, UITableView, IndexPath, SettingsSection.Item)
-> UITableViewCell = {
......@@ -175,6 +194,19 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
cellType: BlockContactsCell.self)
cell.label.text = L10n.Accountpage.blockedContacts
return cell
case .sectionHeader(let title):
let cell = UITableViewCell()
cell.textLabel?.text = title
cell.backgroundColor = UIColor.ringNavigationBar.darken(byPercentage: 0.02)
cell.selectionStyle = .none
return cell
case .ordinary(let label):
let cell = UITableViewCell()
cell.textLabel?.text = label
cell.selectionStyle = .none
return cell
}
}
......@@ -182,10 +214,58 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
self.viewModel.settings
.bind(to: self.settingsTable.rx.items(dataSource: settingsItemDataSource))
.disposed(by: disposeBag)
}
//Set header titles
settingsItemDataSource.titleForHeaderInSection = { dataSource, index in
return dataSource.sectionModels[index].header
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
resetProfileName()
self.profileName.resignFirstResponder()
}
}
extension MeViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let navigationHeight = self.navigationController?.navigationBar.bounds.height
var size = self.view.bounds.size
let screenSize = UIScreen.main.bounds.size
if let height = navigationHeight {
//height for ihoneX
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone,
screenSize.height == 812.0 {
size.height -= (height - 10)
}
}
if scrollView.contentSize.height < size.height {
scrollView.contentSize = size
}
// hide keebord if it was open when user performe scrolling
if self.stretchyHeader.frame.height < self.stretchyHeader.maximumContentHeight * 0.5 {
resetProfileName()
self.profileName.resignFirstResponder()
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.scrollViewDidStopScrolling()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.scrollViewDidStopScrolling()
}
}
private func scrollViewDidStopScrolling() {
var contentOffset = self.settingsTable.contentOffset
if self.stretchyHeader.frame.height <= self.stretchyHeader.minimumContentHeight {
return
}
let middle = (self.stretchyHeader.maximumContentHeight - self.stretchyHeader.minimumContentHeight) * 0.4
if self.stretchyHeader.frame.height > middle {
contentOffset.y = -self.stretchyHeader.maximumContentHeight
} else {
contentOffset.y = -self.stretchyHeader.minimumContentHeight
}
self.settingsTable.setContentOffset(contentOffset, animated: true)
}
}
......@@ -27,54 +27,43 @@ enum SettingsSection: SectionModelType {
typealias Item = SectionRow
case linkedDevices(header: String, items: [SectionRow])
case linkNewDevice(header: String, items: [SectionRow])
case enableProxy(header: String, items: [SectionRow])
case linkedDevices(items: [SectionRow])
case linkNewDevice(items: [SectionRow])
case accountSettings(items: [SectionRow])
case credentials(items: [SectionRow])
enum SectionRow {
case device(device: DeviceModel)
case linkNew
case proxy
case blockedList
}
var header: String {
switch self {
case .linkedDevices(let header, _):
return header
case .linkNewDevice(let header, _):
return header
case .enableProxy(let header, _):
return header
}
case sectionHeader(title: String)
case ordinary(label: String)
}
var items: [SectionRow] {
switch self {
case .linkedDevices(_, let items):
case .linkedDevices(let items):
return items
case .linkNewDevice(_, let items):
case .linkNewDevice(let items):
return items
case .enableProxy(_, let items):
case .accountSettings(let items):
return items
case .credentials(let items):
return items
}
}
public init(original: SettingsSection, items: [SectionRow]) {
switch original {
case .linkedDevices(let header, _):
self = .linkedDevices(header: header, items: items)
case .linkNewDevice(let header, _):
self = .linkNewDevice(header: header, items: items)
case .enableProxy(let header, _):
self = .enableProxy(header: header, items: items)
case .linkedDevices:
self = .linkedDevices(items: items)
case .linkNewDevice:
self = .linkNewDevice(items: items)
case .accountSettings:
self = .accountSettings(items: items)
case .credentials:
self = .credentials(items: items)
}
}
}
......@@ -83,19 +72,28 @@ class MeViewModel: ViewModel, Stateable {
// MARK: - Rx Stateable
private let stateSubject = PublishSubject<State>()
lazy var state: Observable<State> = {
return self.stateSubject.asObservable()
}()
let disposeBag = DisposeBag()
lazy var userName: Observable<String?> = {
let accountService: AccountsService
let nameService: NameService
// MARK: - configure table sections
lazy var userName: Observable<String> = {
// return username if exists, is no start name lookup
let accountName = self.accountService.currentAccount?.volatileDetails?.get(withConfigKeyModel: ConfigKeyModel(withKey: ConfigKey.accountRegisteredName))
if accountName != nil && !accountName!.isEmpty {
return Observable.from(optional: accountName)
}
guard let account = self.accountService.currentAccount else {
return Observable.from(optional: accountName)
return Observable.just("")
}
let accountName = account.volatileDetails?.get(withConfigKeyModel: ConfigKeyModel(withKey: ConfigKey.accountRegisteredName))
if let accountName = accountName, !accountName.isEmpty {
return Observable.just(accountName)
}
let accountHelper = AccountModelHelper(withAccount: account)
guard let uri = accountHelper.ringId else {
return Observable.from(optional: accountName)
return Observable.just("")
}
let time = DispatchTime.now() + 2
DispatchQueue.main.asyncAfter(deadline: time) {
......@@ -111,56 +109,72 @@ class MeViewModel: ViewModel, Stateable {
})
}()
lazy var ringId: Observable<String?> = {
return Observable.from(optional: self.accountService.currentAccount?.details?.get(withConfigKeyModel: ConfigKeyModel(withKey: .accountUsername)))
lazy var ringId: Observable<String> = {
if let uri = self.accountService.currentAccount?.details?.get(withConfigKeyModel: ConfigKeyModel(withKey: .accountUsername)) {
let ringId = uri.replacingOccurrences(of: "ring:", with: "")
return Observable.just(ringId)
}
return Observable.just("")
}()
lazy var state: Observable<State> = {
return self.stateSubject.asObservable()
lazy var accountCredentials: Observable<SettingsSection> = {
return Observable
.combineLatest(userName.startWith(""), ringId.startWith("")) { (name, ringID) in
var items: [SettingsSection.SectionRow] = [.sectionHeader(title: L10n.Accountpage.credentialsHeader),
.ordinary(label: "ringID: " + ringID)]
if !name.isEmpty {
items.append(.ordinary(label: L10n.Accountpage.username + " " + name))
} else {
items.append(.ordinary(label: L10n.Accountpage.usernameNotRegistered))
}
return SettingsSection
.credentials(items: items)
}
}()
let disposeBag = DisposeBag()
let accountService: AccountsService
let nameService: NameService
lazy var linkNewDevice: Observable<SettingsSection> = {
return Observable.just(.linkNewDevice(items: [.linkNew]))
}()
//table section
lazy var settings: Observable<[SettingsSection]> = {
if let account = self.accountService.currentAccount {
let accountHelper = AccountModelHelper(withAccount: account)
let uri = accountHelper.ringId