Commit d28b7488 authored by Thibault Wittemberg's avatar Thibault Wittemberg

project: conform to a swifty way of coding

This commit:
- adapts code to a more Swifty way of coding
- uses previously added frameworks to make the code "type safer"

Change-Id: I5332e2843e82cac4f4f9af79714993863ef5963d
parent 69981855
disabled_rules: # rule identifiers to exclude from running disabled_rules: # rule identifiers to exclude from running
- todo
opt_in_rules: # some rules are only opt-in opt_in_rules: # some rules are only opt-in
- empty_count - empty_count
......
This diff is collapsed.
...@@ -19,8 +19,9 @@ ...@@ -19,8 +19,9 @@
*/ */
import UIKit import UIKit
import Reusable
class AccountTableViewCell: UITableViewCell { class AccountTableViewCell: UITableViewCell, NibReusable {
// MARK: - Properties // MARK: - Properties
@IBOutlet weak var activeSwitch: UISwitch! @IBOutlet weak var activeSwitch: UISwitch!
...@@ -29,15 +30,6 @@ class AccountTableViewCell: UITableViewCell { ...@@ -29,15 +30,6 @@ class AccountTableViewCell: UITableViewCell {
var account: AccountModel! var account: AccountModel!
// MARK: - UITableViewCell
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// MARK: - Actions // MARK: - Actions
@IBAction func switchAccountState(_ sender: UISwitch) { @IBAction func switchAccountState(_ sender: UISwitch) {
// account.isEnabled = sender.isOn // account.isEnabled = sender.isOn
......
...@@ -140,17 +140,11 @@ class CreateRingAccountViewModel { ...@@ -140,17 +140,11 @@ class CreateRingAccountViewModel {
.asObservable().map ({ status in .asObservable().map ({ status in
switch status { switch status {
case .lookingUp: case .lookingUp:
return NSLocalizedString("LookingForUsernameAvailability", return L10n.Createaccount.lookingForUsernameAvailability.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
case .invalid: case .invalid:
return NSLocalizedString("InvalidUsername", return L10n.Createaccount.invalidUsername.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
case .alreadyTaken: case .alreadyTaken:
return NSLocalizedString("UsernameAlreadyTaken", return L10n.Createaccount.usernameAlreadyTaken.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
default: default:
return "" return ""
} }
...@@ -181,7 +175,7 @@ class CreateRingAccountViewModel { ...@@ -181,7 +175,7 @@ class CreateRingAccountViewModel {
//Loookup name request observer //Loookup name request observer
self.username.asObservable().subscribe(onNext: { [unowned self] username in self.username.asObservable().subscribe(onNext: { [unowned self] username in
self.nameService.lookupName(withAccount: "", nameserver: "", name: username) self.nameService.lookupName(withAccount: "", nameserver: "", name: username)
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
//Name registration observer //Name registration observer
self.accountService self.accountService
...@@ -200,7 +194,7 @@ class CreateRingAccountViewModel { ...@@ -200,7 +194,7 @@ class CreateRingAccountViewModel {
name: self.username.value) name: self.username.value)
} }
}) })
.addDisposableTo(disposeBag) .disposed(by: disposeBag)
//Account creation state observer //Account creation state observer
self.accountService self.accountService
...@@ -215,7 +209,7 @@ class CreateRingAccountViewModel { ...@@ -215,7 +209,7 @@ class CreateRingAccountViewModel {
} }
}, onError: { _ in }, onError: { _ in
self.accountCreationState.onError(AccountCreationError.unknown) self.accountCreationState.onError(AccountCreationError.unknown)
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
} }
} }
...@@ -238,34 +232,22 @@ extension AccountCreationError: LocalizedError { ...@@ -238,34 +232,22 @@ extension AccountCreationError: LocalizedError {
var title: String { var title: String {
switch self { switch self {
case .generic: case .generic:
return NSLocalizedString("AccountCannotBeFoundTitle", return L10n.Alerts.accountCannotBeFoundTitle.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
case .network: case .network:
return NSLocalizedString("AccountNoNetworkTitle", return L10n.Alerts.accountNoNetworkTitle.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
default: default:
return NSLocalizedString("AccountDefaultErrorTitle", return L10n.Alerts.accountDefaultErrorTitle.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
} }
} }
var message: String { var message: String {
switch self { switch self {
case .generic: case .generic:
return NSLocalizedString("AcountCannotBeFoundMessage", return L10n.Alerts.accountDefaultErrorMessage.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
case .network: case .network:
return NSLocalizedString("AccountNoNetworkMessage", return L10n.Alerts.accountNoNetworkMessage.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
default: default:
return NSLocalizedString("AccountDefaultErrorMessage", return L10n.Alerts.accountDefaultErrorMessage.smartString
tableName: LocalizedStringTableNames.walkthrough,
comment: "")
} }
} }
} }
...@@ -20,9 +20,16 @@ ...@@ -20,9 +20,16 @@
import Foundation import Foundation
/** public enum Durations {
Time interval between TextField events in seconds case textFieldThrottlingDuration
*/ case alertFlashDuration
let textFieldThrottlingDuration = 0.5
let alertFlashDuration = 1.0 var value: Double {
switch self {
case .textFieldThrottlingDuration:
return 0.5
case .alertFlashDuration:
return 1.0
}
}
}
...@@ -13,64 +13,83 @@ private class RingStringsBundleToken {} ...@@ -13,64 +13,83 @@ private class RingStringsBundleToken {}
// swiftlint:disable valid_docs // swiftlint:disable valid_docs
enum L10n { enum L10n {
/// Account Added
static let accountAddedTitle = L10n.tr("AccountAddedTitle") enum Alerts {
/// Can't find account /// Account Added
static let accountCannotBeFoundTitle = L10n.tr("AccountCannotBeFoundTitle") static let accountAddedTitle = L10n.tr("alerts.accountAddedTitle")
/// The account couldn't be created. /// Can't find account
static let accountDefaultErrorMessage = L10n.tr("AccountDefaultErrorMessage") static let accountCannotBeFoundTitle = L10n.tr("alerts.accountCannotBeFoundTitle")
/// Unknown error /// The account couldn't be created.
static let accountDefaultErrorTitle = L10n.tr("AccountDefaultErrorTitle") static let accountDefaultErrorMessage = L10n.tr("alerts.accountDefaultErrorMessage")
/// Could not add account because Ring couldn't connect to the distributed network. Check your device connectivity. /// Unknown error
static let accountNoNetworkMessage = L10n.tr("AccountNoNetworkMessage") static let accountDefaultErrorTitle = L10n.tr("alerts.accountDefaultErrorTitle")
/// Can't connect to the network /// Could not add account because Ring couldn't connect to the distributed network. Check your device connectivity.
static let accountNoNetworkTitle = L10n.tr("AccountNoNetworkTitle") static let accountNoNetworkMessage = L10n.tr("alerts.accountNoNetworkMessage")
/// 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. /// Can't connect to the network
static let acountCannotBeFoundMessage = L10n.tr("AcountCannotBeFoundMessage") static let accountNoNetworkTitle = L10n.tr("alerts.accountNoNetworkTitle")
/// Choose strong password you will remember to protect your Ring account. /// 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 chooseStrongPassword = L10n.tr("ChooseStrongPassword") static let acountCannotBeFoundMessage = L10n.tr("alerts.acountCannotBeFoundMessage")
/// Conversations }
static let conversations = L10n.tr("Conversations")
/// Create a Ring account enum Createaccount {
static let createAccount = L10n.tr("CreateAccount") /// Choose strong password you will remember to protect your Ring account.
/// Create your Ring account static let chooseStrongPassword = L10n.tr("createAccount.chooseStrongPassword")
static let createAccountFormTitle = L10n.tr("CreateAccountFormTitle") /// Create your Ring account
/// Enter new username static let createAccountFormTitle = L10n.tr("createAccount.createAccountFormTitle")
static let enterNewUsernamePlaceholder = L10n.tr("EnterNewUsernamePlaceholder") /// Enter new username
/// Home static let enterNewUsernamePlaceholder = L10n.tr("createAccount.enterNewUsernamePlaceholder")
static let homeTabBarTitle = L10n.tr("HomeTabBarTitle") /// Invalid username
/// Invalid username static let invalidUsername = L10n.tr("createAccount.invalidUsername")
static let invalidUsername = L10n.tr("InvalidUsername") /// Loading...
/// Link this device to an account static let loading = L10n.tr("createAccount.loading")
static let linkDeviceButton = L10n.tr("LinkDeviceButton") /// Looking for username availability...
/// Looking for username availability... static let lookingForUsernameAvailability = L10n.tr("createAccount.lookingForUsernameAvailability")
static let lookingForUsernameAvailability = L10n.tr("LookingForUsernameAvailability") /// New Password
/// New Password static let newPasswordPlaceholder = L10n.tr("createAccount.newPasswordPlaceholder")
static let newPasswordPlaceholder = L10n.tr("NewPasswordPlaceholder") /// 6 characters minimum
/// No results static let passwordCharactersNumberError = L10n.tr("createAccount.passwordCharactersNumberError")
static let noResults = L10n.tr("NoResults") /// Passwords do not match
/// 6 characters minimum static let passwordNotMatchingError = L10n.tr("createAccount.passwordNotMatchingError")
static let passwordCharactersNumberError = L10n.tr("PasswordCharactersNumberError") /// Register public username (experimental)
/// Passwords do not match static let registerPublicUsername = L10n.tr("createAccount.registerPublicUsername")
static let passwordNotMatchingError = L10n.tr("PasswordNotMatchingError") /// Repeat new password
/// Register public username (experimental) static let repeatPasswordPlaceholder = L10n.tr("createAccount.repeatPasswordPlaceholder")
static let registerPublicUsername = L10n.tr("RegisterPublicUsername") /// Username already taken
/// Repeat new password static let usernameAlreadyTaken = L10n.tr("createAccount.usernameAlreadyTaken")
static let repeatPasswordPlaceholder = L10n.tr("RepeatPasswordPlaceholder") /// Adding account
/// Searching... static let waitCreateAccountTitle = L10n.tr("createAccount.waitCreateAccountTitle")
static let searching = L10n.tr("Searching") }
/// User found
static let userFound = L10n.tr("UserFound") enum Global {
/// Username already taken /// Home
static let usernameAlreadyTaken = L10n.tr("UsernameAlreadyTaken") static let homeTabBarTitle = L10n.tr("global.homeTabBarTitle")
/// Adding account /// Ok
static let waitCreateAccountTitle = L10n.tr("WaitCreateAccountTitle") static let ok = L10n.tr("global.ok")
/// A Ring account allows you to reach people securely in peer to peer through fully distributed network }
static let welcomeText = L10n.tr("WelcomeText")
/// Welcome to Ring enum Smartlist {
static let welcomeTitle = L10n.tr("WelcomeTitle") /// Conversations
/// Yesterday static let conversations = L10n.tr("smartlist.conversations")
static let yesterday = L10n.tr("Yesterday") /// No results
static let noResults = L10n.tr("smartlist.noResults")
/// Searching...
static let searching = L10n.tr("smartlist.searching")
/// User found
static let userFound = L10n.tr("smartlist.userFound")
/// Yesterday
static let yesterday = L10n.tr("smartlist.yesterday")
}
enum Welcome {
/// Create a Ring account
static let createAccount = L10n.tr("welcome.createAccount")
/// Link this device to an account
static let linkDeviceButton = L10n.tr("welcome.linkDeviceButton")
/// A Ring account allows you to reach people securely in peer to peer through fully distributed network
static let text = L10n.tr("welcome.text")
/// Welcome to Ring
static let title = L10n.tr("welcome.title")
}
} }
struct LocalizableString { struct LocalizableString {
......
...@@ -39,7 +39,7 @@ class ContactHelper { ...@@ -39,7 +39,7 @@ class ContactHelper {
} else { } else {
userName.value = lookupNameResponse.address userName.value = lookupNameResponse.address
} }
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
nameService.lookupAddress(withAccount: "", nameserver: "", address: ringId) nameService.lookupAddress(withAccount: "", nameserver: "", address: ringId)
......
...@@ -73,7 +73,7 @@ class ContactViewModel { ...@@ -73,7 +73,7 @@ class ContactViewModel {
} else { } else {
self.userName.value = lookupNameResponse.address self.userName.value = lookupNameResponse.address
} }
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
nameService.lookupAddress(withAccount: "", nameserver: "", address: self.contact.ringId) nameService.lookupAddress(withAccount: "", nameserver: "", address: self.contact.ringId)
} }
......
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
import UIKit import UIKit
import RxSwift import RxSwift
import Reusable
class ConversationCell: UITableViewCell { class ConversationCell: UITableViewCell, NibReusable {
@IBOutlet weak var profileImage: UIImageView! @IBOutlet weak var profileImage: UIImageView!
@IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var nameLabel: UILabel!
...@@ -30,11 +31,6 @@ class ConversationCell: UITableViewCell { ...@@ -30,11 +31,6 @@ class ConversationCell: UITableViewCell {
@IBOutlet weak var lastMessageDateLabel: UILabel! @IBOutlet weak var lastMessageDateLabel: UILabel!
@IBOutlet weak var lastMessagePreviewLabel: UILabel! @IBOutlet weak var lastMessagePreviewLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) { override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated) super.setSelected(selected, animated: animated)
self.newMessagesIndicator.backgroundColor = UIColor.red self.newMessagesIndicator.backgroundColor = UIColor.red
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<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="12088"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<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>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ConversationCellId" rowHeight="76" id="KGk-i7-Jjw" customClass="ConversationCell" customModule="Ring" customModuleProvider="target"> <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="76" id="KGk-i7-Jjw" customClass="ConversationCell" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="358" height="76"/> <rect key="frame" x="0.0" y="0.0" width="358" height="76"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="358" height="76"/> <rect key="frame" x="0.0" y="0.0" width="358" height="75.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_contact_picture" translatesAutoresizingMaskIntoConstraints="NO" id="pFB-Jn-TNP"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_contact_picture" translatesAutoresizingMaskIntoConstraints="NO" id="pFB-Jn-TNP">
......
...@@ -71,7 +71,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate { ...@@ -71,7 +71,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
} }
func setupUI() { func setupUI() {
self.viewModel?.userName.asObservable().bind(to: self.navigationItem.rx.title).addDisposableTo(disposeBag) self.viewModel?.userName.asObservable().bind(to: self.navigationItem.rx.title).disposed(by: disposeBag)
self.tableView.contentInset.bottom = messageAccessoryView.frame.size.height self.tableView.contentInset.bottom = messageAccessoryView.frame.size.height
self.tableView.scrollIndicatorInsets.bottom = messageAccessoryView.frame.size.height self.tableView.scrollIndicatorInsets.bottom = messageAccessoryView.frame.size.height
...@@ -97,22 +97,21 @@ class ConversationViewController: UIViewController, UITextFieldDelegate { ...@@ -97,22 +97,21 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
self.tableView.separatorStyle = .none self.tableView.separatorStyle = .none
//Register cell //Register cell
self.tableView.register(UINib.init(nibName: "MessageCell", bundle: nil), self.tableView.register(cellType: MessageCell.self)
forCellReuseIdentifier: "MessageCellId")
//Bind the TableView to the ViewModel //Bind the TableView to the ViewModel
self.viewModel?.messages self.viewModel?.messages
.bind(to: tableView.rx.items(cellIdentifier: "MessageCellId", .bind(to: tableView.rx.items(cellIdentifier: "MessageCell",
cellType: MessageCell.self)) { _, messageViewModel, cell in cellType: MessageCell.self)) { _, messageViewModel, cell in
cell.messageLabel.text = messageViewModel.content cell.messageLabel.text = messageViewModel.content
cell.bubblePosition = messageViewModel.bubblePosition() cell.bubblePosition = messageViewModel.bubblePosition()
}.addDisposableTo(disposeBag) }.disposed(by: disposeBag)
//Scroll to bottom when reloaded //Scroll to bottom when reloaded
self.tableView.rx.methodInvoked(#selector(UITableView.reloadData)).subscribe(onNext: { _ in self.tableView.rx.methodInvoked(#selector(UITableView.reloadData)).subscribe(onNext: { _ in
self.scrollToBottomIfNeed() self.scrollToBottomIfNeed()
self.updateBottomOffset() self.updateBottomOffset()
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
} }
fileprivate func updateBottomOffset() { fileprivate func updateBottomOffset() {
...@@ -153,7 +152,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate { ...@@ -153,7 +152,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
} }
lazy var messageAccessoryView: MessageAccessoryView = { lazy var messageAccessoryView: MessageAccessoryView = {
return MessageAccessoryView.instanceFromNib() return MessageAccessoryView.loadFromNib()
}() }()
func setupBindings() { func setupBindings() {
...@@ -162,7 +161,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate { ...@@ -162,7 +161,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
self.messageAccessoryView.messageTextField.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: { _ in self.messageAccessoryView.messageTextField.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: { _ in
self.viewModel?.sendMessage(withContent: self.messageAccessoryView.messageTextField.text!) self.viewModel?.sendMessage(withContent: self.messageAccessoryView.messageTextField.text!)
self.messageAccessoryView.messageTextField.text = "" self.messageAccessoryView.messageTextField.text = ""
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
} }
// Avoid the keyboard to be hidden when the Send button is touched // Avoid the keyboard to be hidden when the Send button is touched
......
...@@ -89,7 +89,7 @@ class ConversationViewModel { ...@@ -89,7 +89,7 @@ class ConversationViewModel {
self.log.error("Realm persistence with error: \(error)") self.log.error("Realm persistence with error: \(error)")
} }
}).addDisposableTo(self.disposeBag) }).disposed(by: self.disposeBag)
return tmp return tmp
} }
...@@ -134,7 +134,7 @@ class ConversationViewModel { ...@@ -134,7 +134,7 @@ class ConversationViewModel {
if todayDay == day && todayMonth == month && todayYear == year { if todayDay == day && todayMonth == month && todayYear == year {
return hourFormatter.string(from: lastMessageDate) return hourFormatter.string(from: lastMessageDate)
} else if day == todayDay - 1 { } else if day == todayDay - 1 {
return NSLocalizedString("Yesterday", tableName: "Smartlist", comment: "") return L10n.Smartlist.yesterday.smartString
} else if todayYear == year && todayWeekOfYear == weekOfYear { } else if todayYear == year && todayWeekOfYear == weekOfYear {
return lastMessageDate.dayOfWeek() return lastMessageDate.dayOfWeek()
} else { } else {
...@@ -158,7 +158,7 @@ class ConversationViewModel { ...@@ -158,7 +158,7 @@ class ConversationViewModel {
.subscribe(onCompleted: { .subscribe(onCompleted: {
let accountHelper = AccountModelHelper(withAccount: self.accountService.currentAccount!) let accountHelper = AccountModelHelper(withAccount: self.accountService.currentAccount!)
self.saveMessage(withContent: content, byAuthor: accountHelper.ringId!, toConversationWith: (self.conversation.recipient?.ringId)!) self.saveMessage(withContent: content, byAuthor: accountHelper.ringId!, toConversationWith: (self.conversation.recipient?.ringId)!)
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
} }
fileprivate func saveMessage(withContent content: String, byAuthor author: String, toConversationWith account: String) { fileprivate func saveMessage(withContent content: String, byAuthor author: String, toConversationWith account: String) {
...@@ -167,7 +167,7 @@ class ConversationViewModel { ...@@ -167,7 +167,7 @@ class ConversationViewModel {
.subscribe(onCompleted: { [unowned self] in .subscribe(onCompleted: { [unowned self] in
self.log.debug("Message saved") self.log.debug("Message saved")
}) })
.addDisposableTo(disposeBag) .disposed(by: disposeBag)
} }
func setMessagesAsRead() { func setMessagesAsRead() {
...@@ -175,7 +175,7 @@ class ConversationViewModel { ...@@ -175,7 +175,7 @@ class ConversationViewModel {
.setMessagesAsRead(forConversation: self.conversation) .setMessagesAsRead(forConversation: self.conversation)
.subscribe(onCompleted: { [unowned self] in .subscribe(onCompleted: { [unowned self] in
self.log.debug("Message set as read") self.log.debug("Message set as read")
}).addDisposableTo(disposeBag) }).disposed(by: disposeBag)
} }
fileprivate var unreadMessagesCount: Int { fileprivate var unreadMessagesCount: Int {
......
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Thibault Wittemberg <thibault.wittemberg@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.
*/
import Foundation
extension Bool {
func toString() -> String {
return self ? "true" : "false"
}
}
...@@ -22,22 +22,13 @@ import Foundation ...@@ -22,22 +22,13 @@ import Foundation
extension String { extension String {
func toBool() -> Bool? { func toBool() -> Bool? {
switch self { switch self.lowercased() {
case "True", "true", "yes", "1": case "true", "yes", "1":
return true return true
case "False", "false", "no", "0": case "false", "no", "0":
return false return false
default: default:
return nil return nil
} }
} }
} }
extension Bool {
func toString() -> String {
if self == true {
return "true"
}
return "false"
}
}
/* /*
* Copyright (C) 2017 Savoir-faire Linux Inc. * Copyright (C) 2016 Savoir-faire Linux Inc.
* *
* Author: Silbino Gonçalves Matado <silbino.gmatado@savoirfairelinux.com> * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -18,20 +18,14 @@ ...@@ -18,20 +18,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
import Foundation
import UIKit import UIKit
class RoundedTextField: UITextField { extension UIColor {
required init?(coder aDecoder: NSCoder) { static let ringMain = UIColor(colorLiteralRed: 10.0/255.0,
super.init(coder: aDecoder) green: 116.0/255.0,
self.layer.borderColor = UIColor.white.cgColor blue: 137.0/255.0,
self.layer.borderWidth = 1.0 alpha: 1.0)
self.clipsToBounds = true
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.size.height / 2.0
}
} }