Commit 2a965ee1 authored by Quentin Muret's avatar Quentin Muret Committed by Andreas Traczyk

QR Code feature

- Possibility to generete QR code of our Ring id
- Possibility to scan QR code to add contact
- When we scan a new contact, the conversation page of the contact
 is automatically displayed

Change-Id: I060a641acfff6b15ed6b98e7b9deb52a9f9db887
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 28c7be4b
......@@ -280,7 +280,10 @@
62DFAB2E1F9FF0D0002D6F9C /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */; };
62E55B6D1F758E6F00D3FEF4 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */; };
62E55B6F1F793ADE00D3FEF4 /* AvatarsColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */; };
6613A612214AFF4700B497D1 /* ScanViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6613A611214AFF4700B497D1 /* ScanViewController.storyboard */; };
66266FC021557D2F002757A6 /* ScanViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66266FBF21557D2F002757A6 /* ScanViewModel.swift */; };
66266FC4215C18F8002757A6 /* Emoji+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66266FC3215C18F8002757A6 /* Emoji+Helpers.swift */; };
66ACB430214AE28C00A94162 /* ScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66ACB42F214AE28C00A94162 /* ScanViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -646,7 +649,10 @@
62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = "<group>"; };
62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = "<group>"; };
62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarsColors.swift; sourceTree = "<group>"; };
6613A611214AFF4700B497D1 /* ScanViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ScanViewController.storyboard; sourceTree = "<group>"; };
66266FBF21557D2F002757A6 /* ScanViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanViewModel.swift; sourceTree = "<group>"; };
66266FC3215C18F8002757A6 /* Emoji+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Emoji+Helpers.swift"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
66ACB42F214AE28C00A94162 /* ScanViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -924,6 +930,7 @@
043999F51D1C2D9D00E99CD9 /* Ring */ = {
isa = PBXGroup;
children = (
02E1A0271DDE4C3900D75B59 /* Account */,
0E44B62D202B9DC40060F71B /* Helpers */,
0E63F1F3202907090001F248 /* Ring.entitlements */,
0E0FF1A81FC38409003898C2 /* Database */,
......@@ -936,7 +943,6 @@
1A0C4EBC1F1D48AA00550433 /* Features */,
1ABE07C61F0D86B300D36361 /* Resources */,
02EFCACF1E0C3DD600FD8ED1 /* Bridging */,
02E1A0271DDE4C3900D75B59 /* Account */,
043866341D22D04E00E06CE2 /* UI */,
043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */,
1ABE07DD1F0D91A800D36361 /* LaunchScreen.storyboard */,
......@@ -1183,6 +1189,7 @@
1A0C4EBC1F1D48AA00550433 /* Features */ = {
isa = PBXGroup;
children = (
6613A610214AF8B100B497D1 /* QRCode */,
0E3BD4222044770000A50DDF /* Contact */,
5CE66F721FBF765D00EE9291 /* InitialLoading */,
0E4909711FEAC822005CAA50 /* Calls */,
......@@ -1492,6 +1499,16 @@
name = Cells;
sourceTree = "<group>";
};
6613A610214AF8B100B497D1 /* QRCode */ = {
isa = PBXGroup;
children = (
66ACB42F214AE28C00A94162 /* ScanViewController.swift */,
66266FBF21557D2F002757A6 /* ScanViewModel.swift */,
6613A611214AFF4700B497D1 /* ScanViewController.storyboard */,
);
path = QRCode;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
......@@ -1691,6 +1708,7 @@
0E2D5F551F9145F200D574BF /* LinkNewDeviceCell.xib in Resources */,
1A2D18ED1F2919D800B2C785 /* MeViewController.storyboard in Resources */,
0E35C10D2077DFF000BBA5E3 /* NotificationCell.xib in Resources */,
6613A612214AFF4700B497D1 /* ScanViewController.storyboard in Resources */,
1A20417E1F1E8DDA00C08435 /* CreateProfileViewController.storyboard in Resources */,
0EAA9DB52029F0AA005E245C /* ProxyCell.xib in Resources */,
1ABE07DF1F0D91A800D36361 /* LaunchScreen.storyboard in Resources */,
......@@ -1840,6 +1858,7 @@
1A2D18D81F2918EE00B2C785 /* MeDetailViewController.swift in Sources */,
02B22E091DF7585F000358C9 /* DaemonService.swift in Sources */,
5CE66F761FBF769B00EE9291 /* InitialLoadingViewController.swift in Sources */,
66ACB430214AE28C00A94162 /* ScanViewController.swift in Sources */,
56BBC99F1ED714CB00CDAF8B /* MessagesAdapter.mm in Sources */,
0E438A9A204F47E700402900 /* SettingsTableView.swift in Sources */,
0E49096A1FEAB156005CAA50 /* CallsAdapter.mm in Sources */,
......@@ -1945,6 +1964,7 @@
1A5DC02C1F3565250075E8EF /* MeViewController.swift in Sources */,
0EF78DE31FD0AE3000FC6966 /* ConversationsManager.swift in Sources */,
0EAA9DB42029F0AA005E245C /* ProxyCell.swift in Sources */,
66266FC021557D2F002757A6 /* ScanViewModel.swift in Sources */,
1A2041801F1E903B00C08435 /* CreateProfileViewController.swift in Sources */,
66266FC4215C18F8002757A6 /* Emoji+Helpers.swift in Sources */,
0E0FF1B71FC398B3003898C2 /* ConversationDataHepler.swift in Sources */,
......
......@@ -129,7 +129,7 @@ struct AccountModelHelper {
return self.account
}
var ringId: String? {
public var ringId: String? {
let accountUsernameKey = ConfigKeyModel(withKey: ConfigKey.accountUsername)
let accountUsername = self.account.details?.get(withConfigKeyModel: accountUsernameKey)
......
......@@ -60,6 +60,7 @@ internal enum Asset {
internal static let closeIcon = ImageAsset(name: "close_icon")
internal static let contactRequestIcon = ImageAsset(name: "contact_request_icon")
internal static let conversationIcon = ImageAsset(name: "conversation_icon")
internal static let cross = ImageAsset(name: "cross")
internal static let device = ImageAsset(name: "device")
internal static let disableSpeakerphone = ImageAsset(name: "disable_speakerphone")
internal static let doneIcon = ImageAsset(name: "done_icon")
......@@ -69,8 +70,11 @@ internal enum Asset {
internal static let icContactPicture = ImageAsset(name: "ic_contact_picture")
internal static let moreSettings = ImageAsset(name: "more_settings")
internal static let pauseCall = ImageAsset(name: "pause_call")
internal static let qrCode = ImageAsset(name: "qr_code")
internal static let qrCodeScan = ImageAsset(name: "qr_code_scan")
internal static let ringIcon = ImageAsset(name: "ringIcon")
internal static let ringLogo = ImageAsset(name: "ring_logo")
internal static let scan = ImageAsset(name: "scan")
internal static let sendButton = ImageAsset(name: "send_button")
internal static let settingsIcon = ImageAsset(name: "settings_icon")
internal static let shareButton = ImageAsset(name: "share_button")
......@@ -98,6 +102,7 @@ internal enum Asset {
closeIcon,
contactRequestIcon,
conversationIcon,
cross,
device,
disableSpeakerphone,
doneIcon,
......@@ -107,8 +112,11 @@ internal enum Asset {
icContactPicture,
moreSettings,
pauseCall,
qrCode,
qrCodeScan,
ringIcon,
ringLogo,
scan,
sendButton,
settingsIcon,
shareButton,
......
......@@ -117,6 +117,11 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Ring.MeViewController>(storyboard: MeViewController.self)
}
internal enum ScanViewController: StoryboardType {
internal static let storyboardName = "ScanViewController"
internal static let initialScene = InitialSceneType<Ring.ScanViewController>(storyboard: ScanViewController.self)
}
internal enum SmartlistViewController: StoryboardType {
internal static let storyboardName = "SmartlistViewController"
......
......@@ -221,6 +221,13 @@ internal enum L10n {
internal static let waitLinkToAccountTitle = L10n.tr("Localizable", "linkToAccount.waitLinkToAccountTitle")
}
internal enum Scan {
/// Bad QR code
internal static let badQrCode = L10n.tr("Localizable", "scan.badQrCode")
/// Searching…
internal static let search = L10n.tr("Localizable", "scan.search")
}
internal enum Smartlist {
/// Be sure cellular access is granted in your settings
internal static let cellularAccess = L10n.tr("Localizable", "smartlist.cellularAccess")
......
......@@ -35,8 +35,8 @@ extension String {
func isSHA1() -> Bool {
do {
let sha1Regex = try NSRegularExpression(pattern: "[0-9a-f]{40}", options: .caseInsensitive)
if !sha1Regex.matches(in: self, range: NSRange(location: 0, length: self.count)).isEmpty {
let sha1Regex = try NSRegularExpression(pattern: "[0-9a-f]", options: .caseInsensitive)
if !sha1Regex.matches(in: self, range: NSRange(location: 0, length: self.count)).isEmpty && self.count == 40 {
return true
}
} catch {
......
<?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" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" 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="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......
<?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" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" 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="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......
......@@ -37,7 +37,7 @@ enum MessageSequencing {
enum GeneratedMessageType: String {
case receivedContactRequest = "Contact request received"
case contactAdded = "Contact added"
case contactAdded = "Contact added"
case missedIncomingCall = "Missed incoming call"
case missedOutgoingCall = "Missed outgoing call"
case incomingCall = "Incoming call"
......
<?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" colorMatched="YES" initialViewController="Raw-Ee-7sK">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Raw-Ee-7sK">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
......@@ -159,7 +159,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="JSt-CJ-9Vq" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-97.5" y="-1177.8169014084508"/>
<point key="canvasLocation" x="-108" y="-1208.5457271364319"/>
</scene>
<!--View Controller-->
<scene sceneID="YBM-c2-EWl">
......
......@@ -25,6 +25,7 @@ import RxCocoa
import Reusable
import SwiftyBeaver
//Constants
private struct SmartlistConstants {
static let smartlistRowHeight: CGFloat = 64.0
......@@ -54,9 +55,12 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
fileprivate let disposeBag = DisposeBag()
// MARK: functions
@IBAction func openScan() {
self.viewModel.showQRCode()
}
override func viewDidLoad() {
super.viewDidLoad()
self.setupDataSources()
self.setupTableViews()
self.setupSearchBar()
......@@ -110,12 +114,19 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
}
}).disposed(by: self.disposeBag)
self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
self.conversationsTableView.setEditing(editing, animated: true)
let imageScanSearch = UIImage(asset: Asset.qrCodeScan) as UIImage?
let scanButton = UIButton(type: UIButtonType.custom) as UIButton
scanButton.setImage(imageScanSearch, for: .normal)
let scanButtonItem = UIBarButtonItem(customView: scanButton)
scanButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.openScan()
})
.disposed(by: self.disposeBag)
self.navigationItem.rightBarButtonItem = scanButtonItem
}
@objc func keyboardWillShow(withNotification notification: Notification) {
......@@ -178,7 +189,6 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
}
func setupTableViews() {
//Set row height
self.conversationsTableView.rowHeight = SmartlistConstants.smartlistRowHeight
self.searchResultsTableView.rowHeight = SmartlistConstants.smartlistRowHeight
......
......@@ -245,6 +245,11 @@ class SmartlistViewModel: Stateable, ViewModel {
}
func showConversation (withConversationViewModel conversationViewModel: ConversationViewModel) {
self.stateSubject.onNext(ConversationState.conversationDetail(conversationViewModel: conversationViewModel))
self.stateSubject.onNext(ConversationState.conversationDetail(conversationViewModel:
conversationViewModel))
}
func showQRCode() {
self.stateSubject.onNext(ConversationState.qrCode())
}
}
<?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">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" 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"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......
<?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" colorMatched="YES" initialViewController="RuW-kz-iBP">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="RuW-kz-iBP">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
......
......@@ -80,14 +80,24 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
private func configureBindings() {
let infoButton = UIButton(type: .infoLight)
let imageQrCode = UIImage(asset: Asset.qrCode) as UIImage?
let qrCodeButton = UIButton(type: UIButtonType.custom) as UIButton
qrCodeButton.setImage(imageQrCode, for: .normal)
let infoItem = UIBarButtonItem(customView: infoButton)
let qrCodeButtonItem = UIBarButtonItem(customView: qrCodeButton)
infoButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.infoItemTapped()
})
.disposed(by: self.disposeBag)
qrCodeButton.rx.tap.throttle(0.5, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] in
self.qrCodeItemTapped()
})
.disposed(by: self.disposeBag)
self.navigationItem.rightBarButtonItem = infoItem
self.navigationItem.leftBarButtonItem = qrCodeButtonItem
//setup Table
self.settingsTable.estimatedRowHeight = 50
......@@ -142,6 +152,40 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
self.present(alert, animated: true, completion: nil)
}
private func qrCodeItemTapped() {
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
guard let ringId = viewModel.getRingId() else { return }
let imageQRCode = UIImageView(image: generateQRCode(from: ringId))
imageQRCode.layer.cornerRadius = 8.0
imageQRCode.clipsToBounds = true
imageQRCode.translatesAutoresizingMaskIntoConstraints = false
alert.view.addSubview(imageQRCode)
alert.view.addConstraint(NSLayoutConstraint(item: imageQRCode, attribute: .centerX, relatedBy: .equal, toItem: alert.view, attribute: .centerX, multiplier: 1, constant: 0))
alert.view.addConstraint(NSLayoutConstraint(item: imageQRCode, attribute: .centerY, relatedBy: .equal, toItem: alert.view, attribute: .top, multiplier: 1, constant: 0.0))
alert.view.addConstraint(NSLayoutConstraint(item: imageQRCode, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 270))
alert.view.addConstraint(NSLayoutConstraint(item: imageQRCode, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 270))
self.present(alert, animated: true, completion: {
alert.view.superview?.isUserInteractionEnabled = true
alert.view.superview?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.alertControllerBackgroundTapped)))
})
}
@objc func alertControllerBackgroundTapped() {
self.dismiss(animated: true, completion: nil)
}
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 100, y: 100)
if let output = filter.outputImage?.transformed(by: transform) {
return UIImage(ciImage: output)
}
}
return nil
}
private func setUpDataSource() {
let configureCell: (TableViewSectionedDataSource, UITableView, IndexPath, SettingsSection.Item)
......@@ -279,7 +323,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas
}
}
}
func askProxyAddressAlert() {
let alert = UIAlertController(title: L10n.Accountpage.proxyAddressAlert,
message: nil,
......
......@@ -118,6 +118,14 @@ class MeViewModel: ViewModel, Stateable {
return Observable.just("")
}()
public func getRingId() -> String? {
if let uri = self.accountService.currentAccount?.details?.get(withConfigKeyModel: ConfigKeyModel(withKey: .accountUsername)) {
let ringId = uri.replacingOccurrences(of: "ring:", with: "")
return ringId
}
return nil
}
lazy var accountCredentials: Observable<SettingsSection> = {
return Observable
.combineLatest(userName.startWith(""), ringId.startWith("")) { (name, ringID) in
......
<?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" colorMatched="YES" initialViewController="1yn-Mj-8Ek">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="1yn-Mj-8Ek">
<device id="retina5_9" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
......
......@@ -25,6 +25,7 @@ enum ConversationState: State {
case startAudioCall(contactRingId: String, userName: String)
case conversationDetail(conversationViewModel: ConversationViewModel)
case contactDetail(conversationViewModel: ConversationModel)
case qrCode()
}
protocol ConversationNavigation: class {
......@@ -47,10 +48,21 @@ extension ConversationNavigation where Self: Coordinator, Self: StateableRespons
self.showConversation(withConversationViewModel: conversationViewModel)
case .contactDetail(let conversationModel):
self.presentContactInfo(conversation: conversationModel)
case .qrCode():
self.openQRCode()
}
}).disposed(by: self.disposeBag)
}
func openQRCode () {
let scanViewController = ScanViewController.instantiate(with: self.injectionBag);
self.present(viewController: scanViewController,
withStyle: .present,
withAnimation: true,
withStateable: scanViewController.viewModel,
lockWhilePresenting: VCType.conversation.rawValue)
}
func presentContactInfo(conversation: ConversationModel) {
if let flag = self.presentingVC[VCType.contact.rawValue], flag {
return
......
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="lq1-ve-3Zo">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Scan View Controller-->
<scene sceneID="cZ1-s9-rEa">
<objects>
<viewController id="lq1-ve-3Zo" customClass="ScanViewController" customModule="Ring" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="dqW-Pd-ArU">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view alpha="0.59999999999999998" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1GZ-y1-6Ci">
<rect key="frame" x="0.0" y="0.0" width="414" height="87"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Search..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d4O-QD-W70">
<rect key="frame" x="168.33333333333334" y="45" width="77.333333333333343" height="24"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lyv-WP-6Gx">
<rect key="frame" x="14" y="45" width="25" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="8zw-QV-JFH"/>
<constraint firstAttribute="height" constant="25" id="fj4-rY-8ot"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<state key="normal" image="cross"/>
<connections>
<action selector="closeScan:" destination="lq1-ve-3Zo" eventType="touchUpInside" id="viv-qs-bWn"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="d4O-QD-W70" firstAttribute="centerX" secondItem="1GZ-y1-6Ci" secondAttribute="centerX" id="2Dw-y2-HXJ"/>
<constraint firstItem="Lyv-WP-6Gx" firstAttribute="top" secondItem="1GZ-y1-6Ci" secondAttribute="top" constant="45" id="5M6-5m-TRD"/>
<constraint firstAttribute="bottom" secondItem="Lyv-WP-6Gx" secondAttribute="bottom" constant="17" id="heK-5a-D3P"/>
<constraint firstItem="Lyv-WP-6Gx" firstAttribute="top" secondItem="d4O-QD-W70" secondAttribute="top" id="ts8-j4-SQw"/>
<constraint firstItem="Lyv-WP-6Gx" firstAttribute="leading" secondItem="1GZ-y1-6Ci" secondAttribute="leading" constant="14" id="v9X-hK-Vwo"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="scan" translatesAutoresizingMaskIntoConstraints="NO" id="Tk7-iY-1NY">
<rect key="frame" x="82" y="243" width="250" height="250"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="250" id="PpV-of-Dhq"/>
<constraint firstAttribute="height" constant="250" id="kee-rl-tBu"/>
</constraints>
</imageView>
</subviews>
<constraints>
<constraint firstItem="Tk7-iY-1NY" firstAttribute="centerY" secondItem="dqW-Pd-ArU" secondAttribute="centerY" id="1QD-mx-fWb"/>
<constraint firstAttribute="trailing" secondItem="1GZ-y1-6Ci" secondAttribute="trailing" id="9ye-dW-6N1"/>
<constraint firstItem="1GZ-y1-6Ci" firstAttribute="leading" secondItem="dqW-Pd-ArU" secondAttribute="leading" id="FvR-D5-Rju"/>
<constraint firstAttribute="centerYWithinMargins" relation="lessThanOrEqual" secondItem="1GZ-y1-6Ci" secondAttribute="bottom" constant="1000" id="JBX-m0-oD5"/>
<constraint firstItem="1GZ-y1-6Ci" firstAttribute="top" secondItem="dqW-Pd-ArU" secondAttribute="top" id="ZcI-6M-S7T"/>
<constraint firstItem="Tk7-iY-1NY" firstAttribute="centerX" secondItem="1GZ-y1-6Ci" secondAttribute="centerX" id="iin-nl-Xf4"/>
<constraint firstItem="1GZ-y1-6Ci" firstAttribute="width" secondItem="dqW-Pd-ArU" secondAttribute="width" id="lKb-mV-hd7"/>
</constraints>
<viewLayoutGuide key="safeArea" id="fMq-WO-EdK"/>
</view>
<connections>
<outlet property="header" destination="1GZ-y1-6Ci" id="sYp-yH-aMG"/>
<outlet property="scanImage" destination="Tk7-iY-1NY" id="EYE-wA-uoZ"/>
<outlet property="searchTitle" destination="d4O-QD-W70" id="D7n-g4-RkY"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kcY-va-ant" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1476.8115942028987" y="-346.46739130434787"/>
</scene>
</scenes>
<resources>
<image name="cross" width="40" height="40"/>
<image name="scan" width="256" height="256"/>
</resources>
</document>
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.