Fix registration flow / Keep push tokens in sync

* Separate registering an account from registering for push notifications
  * Allows us to complete registration without prompting user for
    notification settings.

UX Changes
----------
* Automatically keep push tokens in sync on startup.
  Push tokens *can* change, though they rarely do. It happens more often
  for people switching between appstore/beta builds.

  fixes #1174

* Show alert with registration failure
  * add secret 8-tap debug log gesture to registration flow

* Move registration to separate flow
  * don't see flash of inbox when first launching

* show useful error messages when given wrong code / no code

* remove background fetch
  We werent using it, but only relying on a side effect of it which is
  no longer necessary.

Code Changes
------------

* More registration logging.

* Install PromiseKit with carthage

  Our dependencies are not yet framework compatible, so we can't use
  cocoapods.

* Merge preferences util "category" into superclass.

  The immediate reason for this is Swift interop was assuming optional
  types were not optional, and exploding when a value was nil.

  This is clearer anyway, since we were treating it like a subclass, and
  it was the only thing using the class anyway.

* auto-genstrings now searches *.swift (and *.h, which was previously
  broken) for translateable strings.

// FREEBIE
This commit is contained in:
Michael Kirk 2016-10-10 16:02:09 -04:00
parent f98e57e164
commit 1dd06a5e6c
52 changed files with 1985 additions and 1217 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Carthage"]
path = Carthage
url = https://github.com/WhisperSystems/Signal-Carthage.git

View File

@ -15,5 +15,5 @@ before_install:
install: travis_wait 30 pod install # OpenSSL takes a long time to compile
script: make
script: make ci

1
Cartfile Normal file
View File

@ -0,0 +1 @@
github "mxcl/PromiseKit"

1
Cartfile.resolved Normal file
View File

@ -0,0 +1 @@
github "mxcl/PromiseKit" "4.0.5"

1
Carthage Submodule

@ -0,0 +1 @@
Subproject commit 859dc35d6a725b36d4f71c7cd774b12723790486

View File

@ -12,17 +12,19 @@ XCODE_BUILD = xcrun xcodebuild -workspace $(SCHEME).xcworkspace -scheme $(SCHEME
default: test
test: pod_install retest
ci: build_dependencies test
pod_install:
build_dependencies:
cd $(WORKING_DIR) && \
git submodule update --init
pod install
carthage build --platform iOS
build: pod_install
build: build_dependencies
cd $(WORKING_DIR) && \
$(XCODE_BUILD) build | xcpretty
retest: optional_early_start_simulator
test: optional_early_start_simulator
cd $(WORKING_DIR) && \
$(XCODE_BUILD) \
-destination '${BUILD_DESTINATION}' \

View File

@ -44,7 +44,7 @@ PODS:
- Reachability (3.2)
- SAMKeychain (1.5.2)
- SCWaveformView (1.0.0)
- SignalServiceKit (0.3.0):
- SignalServiceKit (0.4.0):
- '25519'
- AFNetworking
- AxolotlKit
@ -140,7 +140,7 @@ CHECKOUT OPTIONS:
:commit: 03cde781234ade464dd26914d87e6e95afde1119
:git: https://github.com/WhisperSystems/JSQMessagesViewController.git
SignalServiceKit:
:commit: 03f05f217cd8f058f4371831ca89a4a32f93d511
:commit: 47cad611e5a14127200747667b7ed9f50e8337ce
:git: https://github.com/WhisperSystems/SignalServiceKit.git
SocketRocket:
:commit: 41b57bb2fc292a814f758441a05243eb38457027
@ -164,7 +164,7 @@ SPEC CHECKSUMS:
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
SCWaveformView: 52a96750255d817e300565a80c81fb643e233e07
SignalServiceKit: 8b115cfd63f9b814fa03fe61fd5d38ef9a548460
SignalServiceKit: 5c3877241082a778c8c130e1fed17d0904085205
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
SQLCipher: 4c768761421736a247ed6cf412d9045615d53dff
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c

View File

@ -13,6 +13,9 @@
450873C41D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */; };
450873C71D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */; };
450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */; };
451DE9F81DC18C9500810E42 /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* AccountManager.swift */; };
451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */; };
451DE9FE1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */; };
4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; };
452E3C8E1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */; };
452E3C8F1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */; };
@ -26,11 +29,13 @@
45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */; };
45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F7A1D9C0533008FE134 /* OWSDatabaseMigration.m */; };
45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F7D1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m */; };
456C38961DC7B882007536A7 /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 451DE9F11DC1585F00810E42 /* PromiseKit.framework */; };
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; };
45855F371D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; };
45855F381D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; };
458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458967101DC117CC00E9DD21 /* AccountManagerTest.swift */; };
458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */; };
458E38341D66873D0094BD24 /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */; };
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; };
@ -51,6 +56,9 @@
45C681C81D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */; };
45C681C91D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */; };
45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; };
45CD81A61DBFF8FC004C9430 /* Registration.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CD81A51DBFF8FC004C9430 /* Registration.storyboard */; };
45CD81EF1DC030E7004C9430 /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* AccountManager.swift */; };
45CD81F21DC03A22004C9430 /* OWSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81F11DC03A22004C9430 /* OWSLogger.m */; };
45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 45EB32CE1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m */; };
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */; };
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */; };
@ -72,7 +80,6 @@
76EB057A18170B33006006FC /* OWSContactsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB040918170B33006006FC /* OWSContactsManager.m */; };
76EB058218170B33006006FC /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041318170B33006006FC /* Environment.m */; };
76EB058418170B33006006FC /* LocalizableText.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041518170B33006006FC /* LocalizableText.m */; };
76EB058618170B33006006FC /* PreferencesUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041718170B33006006FC /* PreferencesUtil.m */; };
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041918170B33006006FC /* PropertyListPreferences.m */; };
76EB058A18170B33006006FC /* Release.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041B18170B33006006FC /* Release.m */; };
76EB058C18170B33006006FC /* DnsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB042018170B33006006FC /* DnsManager.m */; };
@ -169,7 +176,7 @@
A1C32D5117A06544000A904E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4D17A0652C000A904E /* AddressBook.framework */; };
A507A3B11A6C60E300BEED0D /* InboxTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A507A3AF1A6C60E300BEED0D /* InboxTableViewCell.xib */; };
A547DD741A70A87800103EC7 /* DJWActionSheet+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = A547DD721A70A87800103EC7 /* DJWActionSheet+OWS.m */; };
A5509ECA1A69AB8B00ABA4BC /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A5509EC91A69AB8B00ABA4BC /* Storyboard.storyboard */; };
A5509ECA1A69AB8B00ABA4BC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A5509EC91A69AB8B00ABA4BC /* Main.storyboard */; };
A5509ECD1A69B1D600ABA4BC /* CountryCodeTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */; };
A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */; };
A5E9D4BB1A65FAD800E4481C /* TSVideoAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */; };
@ -281,7 +288,6 @@
B660F71B1C29988E00687D6E /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041318170B33006006FC /* Environment.m */; };
B660F71C1C29988E00687D6E /* DebugLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = B6C93C4D199567AD00EDF894 /* DebugLogger.m */; };
B660F71D1C29988E00687D6E /* LocalizableText.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041518170B33006006FC /* LocalizableText.m */; };
B660F71E1C29988E00687D6E /* PreferencesUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041718170B33006006FC /* PreferencesUtil.m */; };
B660F71F1C29988E00687D6E /* PropertyListPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041918170B33006006FC /* PropertyListPreferences.m */; };
B660F7201C29988E00687D6E /* Release.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB041B18170B33006006FC /* Release.m */; };
B660F7211C29988E00687D6E /* SignalKeyingStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */; };
@ -531,6 +537,8 @@
450873C51D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncomingMessageCollectionViewCell.h; sourceTree = "<group>"; };
450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSIncomingMessageCollectionViewCell.m; sourceTree = "<group>"; };
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSExpirableMessageView.h; sourceTree = "<group>"; };
451DE9F11DC1585F00810E42 /* PromiseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PromiseKit.framework; path = Carthage/Build/iOS/PromiseKit.framework; sourceTree = "<group>"; };
451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = "<group>"; };
4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; };
4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageEditing.h; sourceTree = "<group>"; };
452E3C8C1D935C77002A45B0 /* OWSConversationSettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsTableViewController.h; sourceTree = "<group>"; };
@ -560,6 +568,8 @@
45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = "<group>"; };
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactAvatarBuilder.h; sourceTree = "<group>"; };
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactAvatarBuilder.m; sourceTree = "<group>"; };
4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
458967101DC117CC00E9DD21 /* AccountManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccountManagerTest.swift; path = Models/AccountManagerTest.swift; sourceTree = "<group>"; };
458E382F1D6682450094BD24 /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; sourceTree = "<group>"; };
458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = "<group>"; };
458E38321D66873D0094BD24 /* OWSLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkDeviceViewController.h; sourceTree = "<group>"; };
@ -585,6 +595,10 @@
45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisplayedMessageCollectionViewCell.m; sourceTree = "<group>"; };
45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSDisplayedMessageCollectionViewCell.xib; sourceTree = "<group>"; };
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Signal/src/util/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; };
45CD81A51DBFF8FC004C9430 /* Registration.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Registration.storyboard; path = Storyboards/Registration.storyboard; sourceTree = "<group>"; };
45CD81EE1DC030E7004C9430 /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
45CD81F01DC03A22004C9430 /* OWSLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLogger.h; sourceTree = "<group>"; };
45CD81F11DC03A22004C9430 /* OWSLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLogger.m; sourceTree = "<group>"; };
45E282DE1D08E67800ADD4C8 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = translations/gl.lproj/Localizable.strings; sourceTree = "<group>"; };
45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.lproj/Localizable.strings; sourceTree = "<group>"; };
45EB32CD1D7465C900735B2E /* OWSLinkedDevicesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkedDevicesTableViewController.h; sourceTree = "<group>"; };
@ -622,8 +636,6 @@
76EB041318170B33006006FC /* Environment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = "<group>"; };
76EB041418170B33006006FC /* LocalizableText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalizableText.h; sourceTree = "<group>"; };
76EB041518170B33006006FC /* LocalizableText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalizableText.m; sourceTree = "<group>"; };
76EB041618170B33006006FC /* PreferencesUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesUtil.h; sourceTree = "<group>"; };
76EB041718170B33006006FC /* PreferencesUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesUtil.m; sourceTree = "<group>"; };
76EB041818170B33006006FC /* PropertyListPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyListPreferences.h; sourceTree = "<group>"; };
76EB041918170B33006006FC /* PropertyListPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PropertyListPreferences.m; sourceTree = "<group>"; };
76EB041A18170B33006006FC /* Release.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Release.h; sourceTree = "<group>"; };
@ -811,7 +823,7 @@
A507A3AF1A6C60E300BEED0D /* InboxTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = InboxTableViewCell.xib; path = "Signal/src/view controllers/InboxTableViewCell.xib"; sourceTree = SOURCE_ROOT; };
A547DD721A70A87800103EC7 /* DJWActionSheet+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "DJWActionSheet+OWS.m"; path = "util/DJWActionSheet+OWS.m"; sourceTree = "<group>"; };
A547DD731A70A87800103EC7 /* DJWActionSheet+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "DJWActionSheet+OWS.h"; path = "util/DJWActionSheet+OWS.h"; sourceTree = "<group>"; };
A5509EC91A69AB8B00ABA4BC /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Storyboard.storyboard; path = Storyboard/Storyboard.storyboard; sourceTree = "<group>"; };
A5509EC91A69AB8B00ABA4BC /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Storyboard/Main.storyboard; sourceTree = "<group>"; };
A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CountryCodeTableViewCell.h; sourceTree = "<group>"; };
A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CountryCodeTableViewCell.m; sourceTree = "<group>"; };
A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ShowGroupMembersViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
@ -1116,6 +1128,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
456C38961DC7B882007536A7 /* PromiseKit.framework in Frameworks */,
4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */,
B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */,
B6FE7EB71ADD62FA00A6D22F /* PushKit.framework in Frameworks */,
@ -1199,6 +1212,8 @@
45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */,
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */,
45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */,
45CD81EE1DC030E7004C9430 /* AccountManager.swift */,
451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */,
);
path = Models;
sourceTree = "<group>";
@ -1207,6 +1222,7 @@
isa = PBXGroup;
children = (
458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */,
458967101DC117CC00E9DD21 /* AccountManagerTest.swift */,
);
name = Models;
sourceTree = "<group>";
@ -1228,6 +1244,16 @@
name = Observers;
sourceTree = "<group>";
};
45CD81A41DBFF8CF004C9430 /* Storyboards */ = {
isa = PBXGroup;
children = (
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */,
A5509EC91A69AB8B00ABA4BC /* Main.storyboard */,
45CD81A51DBFF8FC004C9430 /* Registration.storyboard */,
);
name = Storyboards;
sourceTree = "<group>";
};
70B8009F190C529C0042E3F0 /* Products */ = {
isa = PBXGroup;
children = (
@ -1261,7 +1287,7 @@
76EB03C118170B33006006FC /* src */ = {
isa = PBXGroup;
children = (
A5509EC91A69AB8B00ABA4BC /* Storyboard.storyboard */,
45CD81A41DBFF8CF004C9430 /* Storyboards */,
76EB03C218170B33006006FC /* AppDelegate.h */,
76EB03C318170B33006006FC /* AppDelegate.m */,
76EB03D918170B33006006FC /* audio */,
@ -1338,8 +1364,6 @@
B6C93C4D199567AD00EDF894 /* DebugLogger.m */,
76EB041418170B33006006FC /* LocalizableText.h */,
76EB041518170B33006006FC /* LocalizableText.m */,
76EB041618170B33006006FC /* PreferencesUtil.h */,
76EB041718170B33006006FC /* PreferencesUtil.m */,
76EB041818170B33006006FC /* PropertyListPreferences.h */,
76EB041918170B33006006FC /* PropertyListPreferences.m */,
76EB041A18170B33006006FC /* Release.h */,
@ -1718,6 +1742,8 @@
B62F5E0F1C2980B4000D370C /* NSData+ows_StripToken.m */,
45666F541D9B2827008FE134 /* OWSScrubbingLogFormatter.h */,
45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */,
45CD81F01DC03A22004C9430 /* OWSLogger.h */,
45CD81F11DC03A22004C9430 /* OWSLogger.m */,
);
path = util;
sourceTree = "<group>";
@ -1807,7 +1833,6 @@
isa = PBXGroup;
children = (
A507A3AF1A6C60E300BEED0D /* InboxTableViewCell.xib */,
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */,
);
path = xibs;
sourceTree = "<group>";
@ -1903,6 +1928,7 @@
B660F66C1C29867F00687D6E /* test */ = {
isa = PBXGroup;
children = (
4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */,
458E38381D6699110094BD24 /* Models */,
459C3F0E1C9B3A20003ACF51 /* TSMessageAdapters */,
B660F66D1C29867F00687D6E /* audio */,
@ -2167,6 +2193,7 @@
D221A08C169C9E5E00537ABF /* Frameworks */ = {
isa = PBXGroup;
children = (
451DE9F11DC1585F00810E42 /* PromiseKit.framework */,
4520D8D41D417D8E00123472 /* Photos.framework */,
B6B226961BE4B7D200860F4D /* ContactsUI.framework */,
B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */,
@ -2396,6 +2423,7 @@
D221A087169C9E5E00537ABF /* Resources */,
59C9DBA462715B5C999FFB02 /* [CP] Embed Pods Frameworks */,
3465F381B1856CC06933B3A8 /* [CP] Copy Pods Resources */,
451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */,
);
buildRules = (
);
@ -2418,6 +2446,7 @@
D221A0A7169C9E5F00537ABF /* Resources */,
B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */,
F76686434770E2BBEBD9665A /* [CP] Copy Pods Resources */,
451DE9FB1DC18D4500810E42 /* [Carthage] Copy Frameworks */,
);
buildRules = (
);
@ -2463,6 +2492,7 @@
};
D221A0A9169C9E5F00537ABF = {
DevelopmentTeam = U68MSDN6DR;
LastSwiftMigration = 0800;
TestTargetID = D221A088169C9E5E00537ABF;
};
};
@ -2559,7 +2589,7 @@
files = (
AD41D7B61A6F6F0600241130 /* play_button@2x.png in Resources */,
AD83FF3F1A73426500B5C81A /* audio_pause_button_blue.png in Resources */,
A5509ECA1A69AB8B00ABA4BC /* Storyboard.storyboard in Resources */,
A5509ECA1A69AB8B00ABA4BC /* Main.storyboard in Resources */,
A507A3B11A6C60E300BEED0D /* InboxTableViewCell.xib in Resources */,
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */,
AD83FF421A73426500B5C81A /* audio_play_button.png in Resources */,
@ -2570,6 +2600,7 @@
AD83FF441A73426500B5C81A /* audio_pause_button.png in Resources */,
B6F509971AA53F760068F56A /* Localizable.strings in Resources */,
AD41D7B51A6F6F0600241130 /* play_button.png in Resources */,
45CD81A61DBFF8FC004C9430 /* Registration.storyboard in Resources */,
B633C59D1A1D190B0059AC12 /* endcall@2x.png in Resources */,
FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */,
B633C5D21A1D190B0059AC12 /* savephoto@2x.png in Resources */,
@ -2648,6 +2679,36 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-resources.sh\"\n";
showEnvVarsInLog = 0;
};
451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"$(SRCROOT)/Carthage/Build/iOS/PromiseKit.framework",
);
name = "[Carthage] Copy Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/usr/local/bin/carthage copy-frameworks\n";
};
451DE9FB1DC18D4500810E42 /* [Carthage] Copy Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"$(SRCROOT)/Carthage/Build/iOS/PromiseKit.framework",
);
name = "[Carthage] Copy Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/usr/local/bin/carthage copy-frameworks\n";
};
59C9DBA462715B5C999FFB02 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -2729,17 +2790,18 @@
76EB062418170B33006006FC /* PriorityQueue.m in Sources */,
B6BADBE71B88D1AC0086A80D /* LockInteractionController.m in Sources */,
76EB061A18170B33006006FC /* DiscardingLog.m in Sources */,
45CD81F21DC03A22004C9430 /* OWSLogger.m in Sources */,
76EB05AC18170B33006006FC /* SrtpSocket.m in Sources */,
FCB11D931A12A4AA002F93FB /* FullImageViewController.m in Sources */,
B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */,
B97940271832BD2400BD66CB /* UIUtil.m in Sources */,
4CE0E3771B954546007210CF /* TSAnimatedAdapter.m in Sources */,
76EB05BE18170B33006006FC /* ConfirmPacket.m in Sources */,
76EB058618170B33006006FC /* PreferencesUtil.m in Sources */,
76EB05A818170B33006006FC /* RtpSocket.m in Sources */,
E197B61818BBEC1A00F073E5 /* RemoteIOAudio.m in Sources */,
B67ADDC41989FF8700E1A773 /* RPServerRequestsManager.m in Sources */,
76EB059418170B33006006FC /* HttpManager.m in Sources */,
45CD81EF1DC030E7004C9430 /* AccountManager.swift in Sources */,
76EB05EC18170B33006006FC /* CallState.m in Sources */,
76EB05D218170B33006006FC /* ZrtpInitiator.m in Sources */,
76EB05E018170B33006006FC /* NetworkStream.m in Sources */,
@ -2861,6 +2923,7 @@
76EB05CE18170B33006006FC /* ZrtpHandshakeResult.m in Sources */,
45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */,
B63761EE19E1FBE8005735D1 /* HttpRequestUtil.m in Sources */,
451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */,
76EB05B618170B33006006FC /* MasterSecret.m in Sources */,
76EB05F418170B33006006FC /* CallConnectResult.m in Sources */,
FCFD256F1A151BCB00F4C644 /* NewGroupViewController.m in Sources */,
@ -2940,6 +3003,7 @@
B660F7131C29988E00687D6E /* SoundPlayer.m in Sources */,
B660F7141C29988E00687D6E /* RecentCall.m in Sources */,
B660F7151C29988E00687D6E /* RecentCallManager.m in Sources */,
451DE9F81DC18C9500810E42 /* AccountManager.swift in Sources */,
B660F7161C29988E00687D6E /* GroupContactsResult.m in Sources */,
B660F7171C29988E00687D6E /* OWSContactsManager.m in Sources */,
B660F7181C29988E00687D6E /* CryptoTools.m in Sources */,
@ -2948,7 +3012,6 @@
B660F71B1C29988E00687D6E /* Environment.m in Sources */,
B660F71C1C29988E00687D6E /* DebugLogger.m in Sources */,
B660F71D1C29988E00687D6E /* LocalizableText.m in Sources */,
B660F71E1C29988E00687D6E /* PreferencesUtil.m in Sources */,
B660F71F1C29988E00687D6E /* PropertyListPreferences.m in Sources */,
B660F7201C29988E00687D6E /* Release.m in Sources */,
B660F7211C29988E00687D6E /* SignalKeyingStorage.m in Sources */,
@ -2956,6 +3019,7 @@
B660F7231C29988E00687D6E /* DnsManager.m in Sources */,
B660F7241C29988E00687D6E /* HostNameEndPoint.m in Sources */,
B660F7251C29988E00687D6E /* IgnoredPacketFailure.m in Sources */,
458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */,
B660F7261C29988E00687D6E /* UnrecognizedRequestFailure.m in Sources */,
B660F7271C29988E00687D6E /* RPAPICall.m in Sources */,
B660F7281C29988E00687D6E /* RPServerRequestsManager.m in Sources */,
@ -2982,6 +3046,7 @@
B660F73A1C29988E00687D6E /* EC25KeyAgreementParticipant.m in Sources */,
B660F73B1C29988E00687D6E /* EC25KeyAgreementProtocol.m in Sources */,
B660F73C1C29988E00687D6E /* EvpKeyAgreement.m in Sources */,
451DE9FE1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */,
B660F73D1C29988E00687D6E /* HashChain.m in Sources */,
B660F73E1C29988E00687D6E /* MasterSecret.m in Sources */,
B660F73F1C29988E00687D6E /* NegotiationFailed.m in Sources */,
@ -3311,7 +3376,8 @@
DEVELOPMENT_TEAM = U68MSDN6DR;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
"$(SRCROOT)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@ -3352,7 +3418,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TEST_AFTER_BUILD = YES;
VALID_ARCHS = "arm64 armv7 armv7s i386";
VALID_ARCHS = "arm64 armv7 armv7s";
WRAPPER_EXTENSION = app;
};
name = Debug;
@ -3369,7 +3435,8 @@
DEVELOPMENT_TEAM = U68MSDN6DR;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
"$(SRCROOT)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@ -3410,7 +3477,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "Signal/src/Signal-Bridging-Header.h";
SWIFT_VERSION = 3.0;
TEST_AFTER_BUILD = YES;
VALID_ARCHS = "arm64 armv7 armv7s i386";
VALID_ARCHS = "arm64 armv7 armv7s";
WRAPPER_EXTENSION = app;
};
name = "App Store Release";
@ -3422,13 +3489,13 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Signal.app/Signal";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
FRAMEWORK_SEARCH_PATHS = (
"\"$(SDKROOT)/Developer/Library/Frameworks\"",
"\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(SRCROOT)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_GENERATE_TEST_COVERAGE_FILES = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@ -3451,6 +3518,7 @@
);
INFOPLIST_FILE = "Signal/test/Supporting Files/SignalTests-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)",
@ -3463,6 +3531,9 @@
PRODUCT_BUNDLE_IDENTIFIER = "org.whispersystems.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = SignalTests;
PROVISIONING_PROFILE = "";
SWIFT_OBJC_BRIDGING_HEADER = "Signal/test/SignalTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUNDLE_LOADER)";
VALID_ARCHS = "arm64 armv7s armv7 i386 x86_64";
};
@ -3475,13 +3546,13 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Signal.app/Signal";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
FRAMEWORK_SEARCH_PATHS = (
"\"$(SDKROOT)/Developer/Library/Frameworks\"",
"\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(SRCROOT)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_GENERATE_TEST_COVERAGE_FILES = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@ -3504,6 +3575,7 @@
);
INFOPLIST_FILE = "Signal/test/Supporting Files/SignalTests-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)",
@ -3516,6 +3588,9 @@
PRODUCT_BUNDLE_IDENTIFIER = "org.whispersystems.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = SignalTests;
PROVISIONING_PROFILE = "c15eac58-5aa7-4660-b874-b9f7ed3dab70";
SWIFT_OBJC_BRIDGING_HEADER = "Signal/test/SignalTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUNDLE_LOADER)";
VALID_ARCHS = "arm64 armv7s armv7 i386 x86_64";
};

View File

@ -28,7 +28,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ACDD4720B3F44CB9CE791085C2FBB289"
BlueprintIdentifier = "A17C67DE5BCCF5991DAF479D127CE09E"
BuildableName = "libSignalServiceKit.a"
BlueprintName = "SignalServiceKit"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -93,6 +93,13 @@
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>

View File

@ -5,6 +5,7 @@
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"ABB939127996C66F7E852A780552ADEEF03C6B13" : 0,
"8176314449001F06FB0E5B588C62133EAA2FE911" : 9223372036854775807,
"37054CE35CE656680D6FFFA9EE19249E0D149C5E" : 0,
"5D79A077E31B3FE97A3C6613CBFFDD71C314D14C" : 0,
"90530B99EB0008E7A50951FDFBE02169118FA649" : 0,
@ -13,6 +14,7 @@
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "D0F297E7-A82D-4657-A941-96B268F80ABC",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"ABB939127996C66F7E852A780552ADEEF03C6B13" : "SocketRocket\/",
"8176314449001F06FB0E5B588C62133EAA2FE911" : "Signal-iOS\/Carthage\/",
"37054CE35CE656680D6FFFA9EE19249E0D149C5E" : "SignalServiceKit\/",
"5D79A077E31B3FE97A3C6613CBFFDD71C314D14C" : "Signal-iOS\/",
"90530B99EB0008E7A50951FDFBE02169118FA649" : "JSQMessagesViewController\/",
@ -32,6 +34,11 @@
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "5D79A077E31B3FE97A3C6613CBFFDD71C314D14C"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:michaelkirk\/Signal-Carthage.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8176314449001F06FB0E5B588C62133EAA2FE911"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:WhisperSystems\/JSQMessagesViewController.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",

View File

@ -38,7 +38,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>26315</string>
<string>2.6.4.2</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LOGS_EMAIL</key>
@ -93,7 +93,6 @@
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>fetch</string>
<string>remote-notification</string>
<string>voip</string>
</array>

View File

@ -2,6 +2,9 @@
#import "SignalsViewController.h"
extern NSString *const AppDelegateStoryboardMain;
extern NSString *const AppDelegateStoryboardRegistration;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;

View File

@ -7,20 +7,26 @@
#import "NotificationsManager.h"
#import "OWSContactsManager.h"
#import "OWSStaleNotificationObserver.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "RPAccountManager.h"
#import "Release.h"
#import "TSAccountManager.h"
#import "Signal-Swift.h"
#import "TSMessagesManager.h"
#import "TSPreKeyManager.h"
#import "TSSocketManager.h"
#import "TextSecureKitEnv.h"
#import "VersionMigrations.h"
#import <PastelogKit/Pastelog.h>
#import <PromiseKit/AnyPromise.h>
#import <SignalServiceKit/OWSDisappearingMessagesJob.h>
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSAccountManager.h>
NSString *const AppDelegateStoryboardMain = @"Main";
NSString *const AppDelegateStoryboardRegistration = @"Registration";
static NSString *const kStoryboardName = @"Storyboard";
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
static NSString *const kURLSchemeSGNLKey = @"sgnl";
static NSString *const kURLHostVerifyPrefix = @"verify";
@ -80,13 +86,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[self setupTSKitEnv];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:kStoryboardName bundle:[NSBundle mainBundle]];
UIViewController *viewController =
[storyboard instantiateViewControllerWithIdentifier:kInitialViewControllerIdentifier];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = viewController;
UIStoryboard *storyboard;
if ([TSAccountManager isRegistered]) {
storyboard = [UIStoryboard storyboardWithName:AppDelegateStoryboardMain bundle:[NSBundle mainBundle]];
} else {
storyboard = [UIStoryboard storyboardWithName:AppDelegateStoryboardRegistration bundle:[NSBundle mainBundle]];
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [storyboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
[VersionMigrations performUpdateCheck]; // this call must be made after environment has been initialized because in
@ -101,9 +109,10 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[self prepareScreenProtection];
// Avoid blocking app launch by putting all possible DB access in async thread.
// At this point, potentially lengthy DB locking migrations could be running.
// Avoid blocking app launch by putting all further possible DB access in async thread.
UIApplicationState launchState = application.applicationState;
[TSAccountManager runIfRegistered:^{
[[TSAccountManager sharedInstance] ifRegistered:YES runAsync:^{
if (launchState == UIApplicationStateInactive) {
DDLogWarn(@"The app was launched from inactive");
[TSSocketManager becomeActiveFromForeground];
@ -114,14 +123,34 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
DDLogWarn(@"The app was launched in an unknown way");
}
[[PushManager sharedManager] validateUserNotificationSettings];
OWSAccountManager *accountManager =
[[OWSAccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]
redPhoneAccountManager:[RPAccountManager sharedInstance]];
[OWSSyncPushTokensJob runWithPushManager:[PushManager sharedManager]
accountManager:accountManager
preferences:[Environment preferences]].then(^{
DDLogDebug(@"%@ Successfully ran syncPushTokensJob.", self.tag);
}).catch(^(NSError *_Nonnull error) {
DDLogDebug(@"%@ Failed to run syncPushTokensJob with error: %@", self.tag, error);
});
[TSPreKeyManager refreshPreKeys];
// Clean up any messages that expired since last launch.
[[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]] run];
[AppStoreRating setupRatingLibrary];
}];
[[TSAccountManager sharedInstance] ifRegistered:NO runAsync:^{
dispatch_async(dispatch_get_main_queue(), ^{
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:[Pastelog class]
action:@selector(submitLogs)];
gesture.numberOfTapsRequired = 8;
[self.window addGestureRecognizer:gesture];
});
}];
[AppStoreRating setupRatingLibrary];
return YES;
}
@ -202,12 +231,14 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
return;
}
[TSAccountManager runIfRegistered:^{
// We're double checking that the app is active, to be sure since we can't verify in production env due to code
// signing.
[TSSocketManager becomeActiveFromForeground];
[[Environment getCurrent].contactsManager verifyABPermission];
}];
[[TSAccountManager sharedInstance] ifRegistered:YES
runAsync:^{
// We're double checking that the app is active, to be sure since we
// can't verify in production env due to code
// signing.
[TSSocketManager becomeActiveFromForeground];
[[Environment getCurrent].contactsManager verifyABPermission];
}];
[self removeScreenProtection];
}
@ -376,6 +407,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
return NO;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];

View File

@ -0,0 +1,104 @@
// Created by Michael Kirk on 10/25/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
import Foundation
import PromiseKit
@objc(OWSAccountManager)
class AccountManager : NSObject {
let TAG = "[AccountManager]"
let textSecureAccountManager: TSAccountManager
let redPhoneAccountManager: RPAccountManager
required init(textSecureAccountManager:TSAccountManager, redPhoneAccountManager:RPAccountManager) {
self.textSecureAccountManager = textSecureAccountManager
self.redPhoneAccountManager = redPhoneAccountManager
}
@objc func register(verificationCode: String) -> AnyPromise {
return AnyPromise(register(verificationCode: verificationCode));
}
func register(verificationCode: String) -> Promise<Void> {
return firstly {
Promise { fulfill, reject in
if verificationCode.characters.count == 0 {
let error = OWSErrorWithCodeDescription(.userError,
NSLocalizedString("REGISTRATION_ERROR_BLANK_VERIFICATION_CODE",
comment: "alert body during registration"))
reject(error)
}
fulfill()
}
}.then {
Logger.debug("\(self.TAG) verification code looks well formed.");
return self.registerForTextSecure(verificationCode: verificationCode)
}.then {
Logger.debug("\(self.TAG) successfully registered for TextSecure")
return self.fetchRedPhoneToken()
}.then { (redphoneToken: String) in
Logger.debug("\(self.TAG) successfully fetched redPhone token")
return self.registerForRedPhone(tsToken:redphoneToken)
}.then {
Logger.debug("\(self.TAG) successfully registered with RedPhone")
}
}
func updatePushTokens(pushToken: String, voipToken: String) -> Promise<Void> {
return firstly {
return self.updateTextSecurePushTokens(pushToken: pushToken, voipToken: voipToken)
}.then {
Logger.info("\(self.TAG) Successfully updated text secure push tokens.")
// TODO should be possible to do these in parallel.
// We want to make sure that either can complete independently of the other.
return self.updateRedPhonePushTokens(pushToken:pushToken, voipToken:voipToken)
}.then {
Logger.info("\(self.TAG) Successfully updated red phone push tokens.")
return Promise { fulfill, reject in
fulfill();
}
}
}
private func updateTextSecurePushTokens(pushToken: String, voipToken: String) -> Promise<Void> {
return Promise { fulfill, reject in
self.textSecureAccountManager.registerForPushNotifications(pushToken:pushToken,
voipToken:voipToken,
success:fulfill,
failure:reject)
}
}
private func updateRedPhonePushTokens(pushToken: String, voipToken: String) -> Promise<Void> {
return Promise { fulfill, reject in
self.redPhoneAccountManager.registerForPushNotifications(pushToken:pushToken,
voipToken:voipToken,
success:fulfill,
failure:reject)
}
}
private func registerForTextSecure(verificationCode: String) -> Promise<Void> {
return Promise { fulfill, reject in
self.textSecureAccountManager.verifyAccount(withCode:verificationCode,
success:fulfill,
failure:reject)
}
}
private func fetchRedPhoneToken() -> Promise<String> {
return Promise { fulfill, reject in
self.textSecureAccountManager.obtainRPRegistrationToken(success:fulfill,
failure:reject)
}
}
private func registerForRedPhone(tsToken: String) -> Promise<Void> {
return Promise { fulfill, reject in
self.redPhoneAccountManager.register(withTsToken:tsToken,
success:fulfill,
failure:reject)
}
}
}

View File

@ -0,0 +1,84 @@
// Created by Michael Kirk on 10/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
import Foundation
import PromiseKit
@objc(OWSSyncPushTokensJob)
class SyncPushTokensJob : NSObject {
let TAG = "[SyncPushTokensJob]"
let pushManager: PushManager
let accountManager: AccountManager
let preferences: PropertyListPreferences
var uploadOnlyIfStale = true
required init(pushManager: PushManager, accountManager: AccountManager, preferences: PropertyListPreferences) {
self.pushManager = pushManager
self.accountManager = accountManager
self.preferences = preferences
}
@objc class func run(pushManager: PushManager, accountManager: AccountManager, preferences: PropertyListPreferences) -> AnyPromise {
let job = self.init(pushManager: pushManager, accountManager: accountManager, preferences: preferences)
return AnyPromise(job.run())
}
@objc func run() -> AnyPromise {
return AnyPromise(run())
}
func run() -> Promise<Void> {
Logger.debug("\(TAG) Starting.")
// Required to potentially prompt user for notifications settings
// before `requestPushTokens` will return.
self.pushManager.validateUserNotificationSettings()
return self.requestPushTokens().then { (pushToken: String, voipToken: String) in
if self.preferences.getPushToken() == pushToken && self.preferences.getVoipToken() == voipToken {
Logger.debug("\(self.TAG) push tokens are already up to date.")
if (self.uploadOnlyIfStale) {
return Promise { fulfill, reject in fulfill(); }
} else {
Logger.debug("\(self.TAG) proceeding with upload even though tokens aren't stale")
}
} else {
Logger.debug("\(self.TAG) push tokens changed.")
}
Logger.debug("\(self.TAG) Sending new tokens to account servers.")
return self.accountManager.updatePushTokens(pushToken:pushToken, voipToken:voipToken).then {
Logger.info("\(self.TAG) Recording tokens locally.")
return self.recordNewPushTokens(pushToken:pushToken, voipToken:voipToken);
}
}
}
private func requestPushTokens() -> Promise<(pushToken: String, voipToken: String)> {
return Promise { fulfill, reject in
self.pushManager.requestPushToken(
success: { (pushToken: String, voipToken: String) in
fulfill((pushToken:pushToken, voipToken:voipToken))
},
failure: reject
);
}
}
private func recordNewPushTokens(pushToken: String, voipToken: String) -> Promise<Void> {
Logger.info("\(TAG) Recording new push tokens.")
if (pushToken != self.preferences.getPushToken()) {
Logger.info("\(TAG) Recording new plain push token")
self.preferences.setPushToken(pushToken);
}
if (voipToken != self.preferences.getVoipToken()) {
Logger.info("\(TAG) Recording new voip token")
self.preferences.setVoipToken(voipToken);
}
return Promise { fulfill, reject in fulfill(); }
}
}

View File

@ -1,3 +1,12 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <Foundation/Foundation.h>
#import "OWSLogger.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "RPAccountManager.h"
#import <SignalServiceKit/OWSError.h>
#import <SignalServiceKit/TSAccountManager.h>
#import <SignalServiceKit/TSStorageManager+keyingMaterial.h>

View File

@ -81,7 +81,6 @@
<outlet property="emptyBoxLabel" destination="Srx-i1-WhD" id="wap-un-Cz5"/>
<outlet property="tableView" destination="PaA-ol-uQT" id="nQU-tR-wbL"/>
<segue destination="Duq-aU-MmN" kind="modal" identifier="2.0_6.0_Call_Segue" modalPresentationStyle="fullScreen" modalTransitionStyle="crossDissolve" id="gHJ-y4-zWg"/>
<segue destination="lIF-0m-2N3" kind="modal" identifier="showSignupFlow" id="DR8-fx-0PD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dE8-zB-mtF" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -115,7 +114,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="yXZ-iE-5va" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2294" y="-1539"/>
<point key="canvasLocation" x="-2287" y="-1516"/>
</scene>
<!--Fingerprint View Controller-->
<scene sceneID="ldP-mt-Vsq">
@ -353,11 +352,11 @@
<rect key="frame" x="0.0" y="100" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Dzg-XO-ciX" id="KFb-kN-MV9">
<frame key="frameInset" width="342" height="43.5"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Verify Safety Numbers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Iq5-ca-zUp">
<frame key="frameInset" minX="62" width="278" height="43.5"/>
<frame key="frameInset" minX="62" width="278" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -378,7 +377,7 @@
<rect key="frame" x="0.0" y="144" width="375" height="108"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="U6h-Xo-HEv" id="Nmz-2u-fOY">
<frame key="frameInset" width="375" height="108"/>
<frame key="frameInset" width="375" height="107"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Disappearing Messages" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="qbY-qJ-enK" userLabel="Disappearing Messages">
@ -427,7 +426,7 @@
<rect key="frame" x="0.0" y="252" width="375" height="76"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3dL-aW-P1A" id="2a2-Po-p8O">
<frame key="frameInset" width="375" height="76"/>
<frame key="frameInset" width="375" height="75"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Messages disappear after 8 hours." lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="c6Q-rV-1LO" userLabel="Keep messages for 8 hours.">
@ -470,14 +469,14 @@
<tableViewSection headerTitle="Group Management" id="z5m-Fe-GK8">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="NxZ-wa-xV9" style="IBUITableViewCellStyleDefault" id="XHr-b6-Gvn" userLabel="Update Group">
<rect key="frame" x="0.0" y="384" width="375" height="44"/>
<rect key="frame" x="0.0" y="385" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="XHr-b6-Gvn" id="Epj-vT-UYL">
<frame key="frameInset" width="342" height="43.5"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Update Group" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="NxZ-wa-xV9">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -490,14 +489,14 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="geN-YN-TQg" style="IBUITableViewCellStyleDefault" id="w57-rz-BWN" userLabel="Leave Group">
<rect key="frame" x="0.0" y="428" width="375" height="44"/>
<rect key="frame" x="0.0" y="429" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="w57-rz-BWN" id="Pgy-Fc-U25">
<frame key="frameInset" width="342" height="43.5"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Leave Group" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="geN-YN-TQg">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -507,14 +506,14 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Zml-Zn-2fd" style="IBUITableViewCellStyleDefault" id="Dnq-Ko-46l" userLabel="Group Members">
<rect key="frame" x="0.0" y="472" width="375" height="44"/>
<rect key="frame" x="0.0" y="473" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Dnq-Ko-46l" id="VRQ-31-E5Y">
<frame key="frameInset" width="342" height="43.5"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Group Members" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Zml-Zn-2fd">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -569,7 +568,7 @@
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hyn-Ss-OAa" id="4XE-JO-Upr">
<frame key="frameInset" width="375" height="44"/>
<frame key="frameInset" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
@ -585,305 +584,6 @@
</objects>
<point key="canvasLocation" x="-1032" y="-1540"/>
</scene>
<!--_1.0 Registration Screen-->
<scene sceneID="okO-46-HuB">
<objects>
<viewController storyboardIdentifier="RegistrationViewController" id="sL4-Zw-2Og" userLabel="_1.0 Registration Screen" customClass="RegistrationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="kUb-Rf-uos"/>
<viewControllerLayoutGuide type="bottom" id="g9k-sN-wqg"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Y3I-8Y-pLa" userLabel="_1.0 Registration Screen">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="J5f-8V-ASm" userLabel="_1.0a Registration Screen Title">
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your Phone Number" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="50y-cV-8aI">
<constraints>
<constraint firstAttribute="height" constant="29" id="T1b-ph-zPv"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="hle-PK-Ivk"/>
</subviews>
<color key="backgroundColor" red="0.11356575042009354" green="0.47873002290725708" blue="0.89595204591751099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="50y-cV-8aI" secondAttribute="bottom" constant="26" id="9Ep-V2-rAF"/>
<constraint firstAttribute="centerX" secondItem="50y-cV-8aI" secondAttribute="centerX" constant="-1" id="eOY-3p-Xc8"/>
<constraint firstAttribute="centerX" secondItem="hle-PK-Ivk" secondAttribute="centerX" id="gCK-yC-ldQ"/>
<constraint firstItem="50y-cV-8aI" firstAttribute="top" secondItem="hle-PK-Ivk" secondAttribute="bottom" constant="8" id="hAJ-yW-wpy"/>
<constraint firstAttribute="width" secondItem="50y-cV-8aI" secondAttribute="width" id="xgJ-w1-7oN"/>
<constraint firstAttribute="height" constant="245" id="y0A-n2-Thn"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oS3-t9-5np" userLabel="_1.0b Registration Country Code Selection">
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O6t-0o-mk5">
<color key="backgroundColor" red="0.75549191236495972" green="0.75563699007034302" blue="0.75546777248382568" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="gpg-j8-Tjz"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VvN-1x-NvR">
<constraints>
<constraint firstAttribute="width" constant="67" id="0Oj-m4-j2A"/>
<constraint firstAttribute="height" constant="26" id="IlP-zb-7h9"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<state key="normal" title="+1">
<color key="titleColor" red="0.054103322327136993" green="0.45790460705757141" blue="0.92617350816726685" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="1Vd-tn-37d" kind="modal" id="xo7-5J-BJb"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ngV-Kv-6Ax">
<rect key="contentStretch" x="1" y="0.0" width="1" height="1"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="LOh-ty-lH1"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<state key="normal" title="Country Code">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="1Vd-tn-37d" kind="modal" id="RW4-y4-lZo"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="4z2-Ss-eUR"/>
<constraint firstAttribute="trailing" secondItem="VvN-1x-NvR" secondAttribute="trailing" constant="16" id="Gxg-K6-41b"/>
<constraint firstItem="O6t-0o-mk5" firstAttribute="top" secondItem="oS3-t9-5np" secondAttribute="top" constant="59" id="HiM-Qo-w4K"/>
<constraint firstItem="ngV-Kv-6Ax" firstAttribute="top" secondItem="oS3-t9-5np" secondAttribute="top" id="IAx-hM-15N"/>
<constraint firstItem="O6t-0o-mk5" firstAttribute="leading" secondItem="oS3-t9-5np" secondAttribute="leading" id="LOK-8V-SOa"/>
<constraint firstAttribute="centerY" secondItem="VvN-1x-NvR" secondAttribute="centerY" id="WUv-b0-9lQ"/>
<constraint firstItem="ngV-Kv-6Ax" firstAttribute="leading" secondItem="oS3-t9-5np" secondAttribute="leading" constant="20" id="aY5-4G-kSx"/>
<constraint firstAttribute="trailing" secondItem="ngV-Kv-6Ax" secondAttribute="trailing" constant="105" id="gAb-25-kWY"/>
<constraint firstAttribute="trailing" secondItem="O6t-0o-mk5" secondAttribute="trailing" id="uOf-fI-aak"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tSy-r0-e7H" userLabel="_1.0c Registration Phone Number Input">
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vpp-VC-z9v">
<color key="backgroundColor" red="0.75559091567993164" green="0.75556838512420654" blue="0.75558114051818848" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="SiS-mn-Yud"/>
</constraints>
</view>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Enter Number" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="tTJ-pq-Z9L">
<constraints>
<constraint firstAttribute="width" constant="176" id="6Ux-PV-sZk"/>
<constraint firstAttribute="height" constant="26" id="bkw-ef-Yt9"/>
</constraints>
<color key="textColor" red="0.23574128746986389" green="0.2357865571975708" blue="0.23573371767997742" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<textInputTraits key="textInputTraits" keyboardType="phonePad" keyboardAppearance="light"/>
</textField>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AbN-AU-yk7">
<constraints>
<constraint firstAttribute="height" constant="26" id="hch-s1-zig"/>
<constraint firstAttribute="width" constant="152" id="tZB-hO-p3n"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<state key="normal" title="Phone Number">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tTJ-pq-Z9L" secondAttribute="trailing" constant="16" id="G4f-2B-yOo"/>
<constraint firstAttribute="height" constant="61" id="RtR-L9-Slj"/>
<constraint firstItem="AbN-AU-yk7" firstAttribute="leading" secondItem="tSy-r0-e7H" secondAttribute="leading" constant="20" id="WVz-M2-usI"/>
<constraint firstItem="vpp-VC-z9v" firstAttribute="top" secondItem="tSy-r0-e7H" secondAttribute="top" constant="59" id="cdn-9h-GmB"/>
<constraint firstItem="vpp-VC-z9v" firstAttribute="leading" secondItem="tSy-r0-e7H" secondAttribute="leading" id="iVY-v5-EFw"/>
<constraint firstItem="tTJ-pq-Z9L" firstAttribute="top" secondItem="tSy-r0-e7H" secondAttribute="top" constant="19" id="lvg-cd-jw7"/>
<constraint firstItem="AbN-AU-yk7" firstAttribute="top" secondItem="tSy-r0-e7H" secondAttribute="top" constant="18" id="nGU-YZ-b1a"/>
<constraint firstAttribute="trailing" secondItem="vpp-VC-z9v" secondAttribute="trailing" constant="-40" id="yiy-cf-MET"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g8J-Eg-0PT" userLabel="_1.0d Registration Verification Code Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7IK-hd-tli">
<color key="backgroundColor" red="0.082137122750282288" green="0.46843802928924561" blue="0.91112053394317627" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="47" id="foJ-cw-ajR"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="47" id="gxX-eS-QSu"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
<state key="normal" title="Verify This Device">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeAction:" destination="sL4-Zw-2Og" eventType="touchUpInside" id="T8X-Mx-4I6"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="Uhw-zc-NhO">
<constraints>
<constraint firstAttribute="height" constant="20" id="EN0-Kc-yUf"/>
<constraint firstAttribute="width" constant="20" id="WRq-AE-2aq"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="47" id="2UQ-03-3A5"/>
<constraint firstItem="Uhw-zc-NhO" firstAttribute="trailing" secondItem="7IK-hd-tli" secondAttribute="trailing" constant="-20" id="6gr-Dr-6tX"/>
<constraint firstItem="Uhw-zc-NhO" firstAttribute="top" secondItem="7IK-hd-tli" secondAttribute="top" constant="14" id="ZlI-Yo-dfV"/>
<constraint firstItem="7IK-hd-tli" firstAttribute="top" secondItem="g8J-Eg-0PT" secondAttribute="top" constant="1" id="dux-b4-RDq"/>
<constraint firstItem="7IK-hd-tli" firstAttribute="leading" secondItem="g8J-Eg-0PT" secondAttribute="leading" constant="30" id="u3m-So-Ucs"/>
<constraint firstAttribute="trailing" secondItem="7IK-hd-tli" secondAttribute="trailing" constant="30" id="xb6-vB-DMa"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="oS3-t9-5np" firstAttribute="leading" secondItem="Y3I-8Y-pLa" secondAttribute="leadingMargin" constant="-16" id="3EZ-dN-uSz"/>
<constraint firstItem="oS3-t9-5np" firstAttribute="top" secondItem="J5f-8V-ASm" secondAttribute="bottom" id="71e-hb-Z1h"/>
<constraint firstAttribute="trailingMargin" secondItem="g8J-Eg-0PT" secondAttribute="trailing" constant="-16" id="BWm-zI-175"/>
<constraint firstItem="tSy-r0-e7H" firstAttribute="top" secondItem="oS3-t9-5np" secondAttribute="bottom" id="Fph-pt-xzK"/>
<constraint firstItem="tSy-r0-e7H" firstAttribute="leading" secondItem="Y3I-8Y-pLa" secondAttribute="leadingMargin" constant="-16" id="NvD-GX-gzB"/>
<constraint firstAttribute="trailingMargin" secondItem="oS3-t9-5np" secondAttribute="trailing" constant="-16" id="R4y-T6-4hQ"/>
<constraint firstItem="g8J-Eg-0PT" firstAttribute="top" secondItem="tSy-r0-e7H" secondAttribute="bottom" constant="9" id="RMp-tP-gJl"/>
<constraint firstItem="g8J-Eg-0PT" firstAttribute="leading" secondItem="Y3I-8Y-pLa" secondAttribute="leadingMargin" constant="-16" id="Tiq-gc-mL4"/>
<constraint firstItem="J5f-8V-ASm" firstAttribute="width" secondItem="Y3I-8Y-pLa" secondAttribute="width" id="VC9-DR-mZb"/>
<constraint firstItem="J5f-8V-ASm" firstAttribute="top" secondItem="kUb-Rf-uos" secondAttribute="bottom" constant="-20" id="WnH-Ur-Lz4"/>
<constraint firstAttribute="trailingMargin" secondItem="tSy-r0-e7H" secondAttribute="trailing" constant="-16" id="awv-YP-rng"/>
<constraint firstAttribute="centerX" secondItem="J5f-8V-ASm" secondAttribute="centerX" id="kna-iw-ZWQ"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="5Qk-ka-UUh"/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
<nil key="simulatedTopBarMetrics"/>
<connections>
<outlet property="countryCodeButton" destination="VvN-1x-NvR" id="4lX-oF-LcQ"/>
<outlet property="countryNameButton" destination="ngV-Kv-6Ax" id="g5m-JR-9we"/>
<outlet property="headerHeightConstraint" destination="y0A-n2-Thn" id="qgl-Ww-e2Y"/>
<outlet property="phoneNumberButton" destination="AbN-AU-yk7" id="hyI-4o-0q7"/>
<outlet property="phoneNumberTextField" destination="tTJ-pq-Z9L" id="gPX-pu-twz"/>
<outlet property="sendCodeButton" destination="7IK-hd-tli" id="cs2-wN-txb"/>
<outlet property="signalLogo" destination="hle-PK-Ivk" id="UCb-xs-dgk"/>
<outlet property="spinnerView" destination="Uhw-zc-NhO" id="Qck-ul-rgQ"/>
<outlet property="titleLabel" destination="50y-cV-8aI" id="6X1-kw-gDu"/>
<segue destination="3Uo-Ow-qOD" kind="push" identifier="codeSent" id="KhC-MI-Evx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="rfK-ej-7ve" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3956" y="-732.72000000000003"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="h0n-nM-9Kp">
<objects>
<navigationController id="1Vd-tn-37d" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="fty-2s-xFJ">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" red="0.082137122750282288" green="0.46843802928924561" blue="0.91112053394317627" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<connections>
<segue destination="nT9-Zl-5R0" kind="relationship" relationship="rootViewController" id="mkr-n5-2Nm"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zxR-ej-kvN" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-4372" y="22.719999999999999"/>
</scene>
<!--_2.0_1.0__1 Country Code Modal-->
<scene sceneID="8LH-LS-3Zu">
<objects>
<tableViewController storyboardIdentifier="CountryCodeViewController" id="nT9-Zl-5R0" userLabel="_2.0_1.0__1 Country Code Modal" customClass="CountryCodeViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="o7w-iD-5XF" userLabel="_1.0__1 Country Code Table">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<searchBar key="tableHeaderView" contentMode="redraw" id="Syd-Xl-kCG" userLabel="__1a Search Bar">
<rect key="frame" x="0.0" y="64" width="375" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits"/>
<connections>
<outlet property="delegate" destination="nT9-Zl-5R0" id="dR5-Gb-Tvl"/>
</connections>
</searchBar>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CountryCodeTableViewCell" id="hpG-pz-GPZ" userLabel="__1b Country Code Table" customClass="CountryCodeTableViewCell">
<rect key="frame" x="0.0" y="130" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hpG-pz-GPZ" id="gVo-Nw-ff7" userLabel="Country Code Table Row">
<frame key="frameInset" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="United states" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SDz-Ag-lp3">
<constraints>
<constraint firstAttribute="width" constant="244" id="Y66-3d-yJI"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="2" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="+1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hl9-0w-DHU">
<constraints>
<constraint firstAttribute="width" constant="64" id="S6t-bW-MMl"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="SDz-Ag-lp3" firstAttribute="leading" secondItem="gVo-Nw-ff7" secondAttribute="leadingMargin" constant="12" id="aYr-BL-A9N"/>
<constraint firstAttribute="centerY" secondItem="SDz-Ag-lp3" secondAttribute="centerY" id="d1E-Q7-R5V"/>
<constraint firstAttribute="centerY" secondItem="hl9-0w-DHU" secondAttribute="centerY" id="wyz-ST-eA7"/>
<constraint firstAttribute="trailingMargin" secondItem="hl9-0w-DHU" secondAttribute="trailing" constant="11" id="zEI-fy-DdI"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="countryCodeLabel" destination="hl9-0w-DHU" id="z7K-fi-Cag"/>
<outlet property="countryNameLabel" destination="SDz-Ag-lp3" id="aCl-RV-0Vm"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="nT9-Zl-5R0" id="k2D-aq-CBm"/>
<outlet property="delegate" destination="nT9-Zl-5R0" id="fH6-5P-CqK"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Select Country Code" id="XoD-Ld-9kq" userLabel="_1.0__1c Navigation Bar">
<barButtonItem key="leftBarButtonItem" image="btnCancel--white" id="TGY-g8-Q3E">
<connections>
<segue destination="FyL-dj-xBH" kind="unwind" unwindAction="unwindToCountryCodeSelectionCancelled:" id="RgP-lV-2uZ"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="countryCodeTableView" destination="o7w-iD-5XF" id="xeI-ZV-kYO"/>
<outlet property="searchBar" destination="Syd-Xl-kCG" id="jz3-Gl-MzL"/>
<outlet property="searchDisplayController" destination="vYp-g4-bCc" id="N4c-KY-zJa"/>
<segue destination="FyL-dj-xBH" kind="unwind" identifier="UnwindToCountryCodeWasSelectedSegue" unwindAction="unwindToCountryCodeWasSelected:" id="keR-nB-Y6M"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="OxD-kN-rM9" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="FyL-dj-xBH" userLabel="Exit" sceneMemberID="exit"/>
<searchDisplayController id="vYp-g4-bCc">
<connections>
<outlet property="delegate" destination="nT9-Zl-5R0" id="8jB-sR-ocy"/>
<outlet property="searchContentsController" destination="nT9-Zl-5R0" id="G5Z-Ga-wNR"/>
<outlet property="searchResultsDataSource" destination="nT9-Zl-5R0" id="AC8-Ql-oi7"/>
<outlet property="searchResultsDelegate" destination="nT9-Zl-5R0" id="yUM-Ix-kuj"/>
</connections>
</searchDisplayController>
<navigationItem title="Title" id="1Tt-v6-fTh"/>
</objects>
<point key="canvasLocation" x="-3956" y="22.719999999999999"/>
</scene>
<!--2.0_6.0 - Incoming, Outgoing, Active call-->
<scene sceneID="cEC-6y-6yI">
<objects>
@ -1120,250 +820,6 @@
</objects>
<point key="canvasLocation" x="-2295" y="-2347"/>
</scene>
<!--_1.1 Verification Screen-->
<scene sceneID="44F-BV-mQs">
<objects>
<viewController storyboardIdentifier="CodeVerificationViewController" id="3Uo-Ow-qOD" userLabel="_1.1 Verification Screen" customClass="CodeVerificationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="OuY-yn-ZQb"/>
<viewControllerLayoutGuide type="bottom" id="MHI-1c-yZH"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Zgb-Uj-73M" userLabel="_1.1 Verification Screen">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lIs-Ck-sAt" userLabel="_1.1a Validation Screen Title">
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Verification" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8Y-At-xEK">
<constraints>
<constraint firstAttribute="height" constant="29" id="Mem-ez-9kw"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="gVg-vn-tFu"/>
</subviews>
<color key="backgroundColor" red="0.11356575042009354" green="0.47873002290725708" blue="0.89595204591751099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="245" id="5bj-kr-L4s" userLabel="Height - (245) - _1.1 Registration Screen Title"/>
<constraint firstAttribute="centerX" secondItem="gVg-vn-tFu" secondAttribute="centerX" constant="-1" id="BYD-AS-JGx"/>
<constraint firstAttribute="width" secondItem="e8Y-At-xEK" secondAttribute="width" id="Dso-vy-b1P"/>
<constraint firstAttribute="centerX" secondItem="e8Y-At-xEK" secondAttribute="centerX" constant="-1" id="OE3-vm-S0c"/>
<constraint firstItem="e8Y-At-xEK" firstAttribute="top" secondItem="gVg-vn-tFu" secondAttribute="bottom" constant="8" id="Tyg-if-gYi"/>
<constraint firstAttribute="bottom" secondItem="e8Y-At-xEK" secondAttribute="bottom" constant="25" id="i3h-X2-WTD"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XXt-2F-6KC" userLabel="_1.1b Verification Code Input">
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Verification Code" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="yK6-ad-ihc">
<constraints>
<constraint firstAttribute="width" constant="401" id="aPy-KQ-lfQ"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="21"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad" keyboardAppearance="alert"/>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="260-Dq-fnd">
<color key="backgroundColor" red="0.75559091567993164" green="0.75556838512420654" blue="0.75558114051818848" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="OPE-jg-ZYz"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="260-Dq-fnd" secondAttribute="trailing" constant="36" id="0sO-fC-DMj"/>
<constraint firstAttribute="centerX" secondItem="yK6-ad-ihc" secondAttribute="centerX" constant="-0.5" id="3S2-pc-LF2"/>
<constraint firstAttribute="centerX" secondItem="260-Dq-fnd" secondAttribute="centerX" id="Cpz-Xr-PyY"/>
<constraint firstItem="260-Dq-fnd" firstAttribute="top" secondItem="XXt-2F-6KC" secondAttribute="top" constant="26" id="JUC-mX-txh"/>
<constraint firstAttribute="height" secondItem="yK6-ad-ihc" secondAttribute="height" id="Ngq-Yp-juC"/>
<constraint firstAttribute="height" constant="32" id="ZsF-lO-3P6"/>
<constraint firstItem="yK6-ad-ihc" firstAttribute="top" secondItem="XXt-2F-6KC" secondAttribute="top" id="kVs-z9-Ipc"/>
<constraint firstItem="260-Dq-fnd" firstAttribute="leading" secondItem="XXt-2F-6KC" secondAttribute="leading" constant="36" id="pJW-IT-QUO"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="95o-ce-XGu" userLabel="_1.1c Verification Verify Code Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Nx-nz-ht7">
<color key="backgroundColor" red="0.082137122750282288" green="0.46843802928924561" blue="0.91112053394317627" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="47" id="ote-hy-MTP"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<state key="normal" title="Submit Verification Code">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="verifyChallengeAction:" destination="3Uo-Ow-qOD" eventType="touchUpInside" id="xhB-mH-aQJ"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="vmS-8s-cvA">
<constraints>
<constraint firstAttribute="width" constant="20" id="IkO-na-VRc"/>
<constraint firstAttribute="height" constant="20" id="rNO-wM-YcD"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="5Nx-nz-ht7" firstAttribute="leading" secondItem="95o-ce-XGu" secondAttribute="leading" constant="36" id="1C6-X7-eAN"/>
<constraint firstItem="vmS-8s-cvA" firstAttribute="trailing" secondItem="5Nx-nz-ht7" secondAttribute="trailing" constant="-15" id="NKV-4w-3iV"/>
<constraint firstItem="5Nx-nz-ht7" firstAttribute="top" secondItem="95o-ce-XGu" secondAttribute="top" id="Yd9-hW-I38"/>
<constraint firstAttribute="trailing" secondItem="5Nx-nz-ht7" secondAttribute="trailing" constant="36" id="gb0-Cl-5TE"/>
<constraint firstItem="vmS-8s-cvA" firstAttribute="top" secondItem="5Nx-nz-ht7" secondAttribute="top" constant="14" id="h9J-Cx-dkh"/>
<constraint firstAttribute="height" constant="47" id="sPb-zU-Xyo"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UWb-Di-S2f" userLabel="_1.1d Verification Send Again Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9dl-sl-tZN">
<constraints>
<constraint firstAttribute="height" constant="47" id="giC-el-dFa"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<state key="normal" title="Request Code Again">
<color key="titleColor" red="0.081759713590145111" green="0.46913978457450867" blue="0.91040575504302979" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeSMSAction:" destination="3Uo-Ow-qOD" eventType="touchUpInside" id="a2S-fL-uqx"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="utk-2S-Qc7">
<constraints>
<constraint firstAttribute="height" constant="20" id="nY2-Ab-Abc"/>
<constraint firstAttribute="width" constant="20" id="w86-JO-TiH"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="utk-2S-Qc7" firstAttribute="top" secondItem="UWb-Di-S2f" secondAttribute="top" constant="14" id="FZK-Y5-nhN"/>
<constraint firstItem="utk-2S-Qc7" firstAttribute="trailing" secondItem="9dl-sl-tZN" secondAttribute="trailing" constant="-14" id="Fcp-qj-flP"/>
<constraint firstAttribute="trailing" secondItem="9dl-sl-tZN" secondAttribute="trailing" constant="36" id="GmS-Bf-C4e"/>
<constraint firstItem="9dl-sl-tZN" firstAttribute="leading" secondItem="UWb-Di-S2f" secondAttribute="leading" constant="36" id="IXU-Ib-8RK"/>
<constraint firstAttribute="height" constant="47" id="M2M-ox-Y9r"/>
<constraint firstItem="9dl-sl-tZN" firstAttribute="top" secondItem="UWb-Di-S2f" secondAttribute="top" id="PI1-Zh-nf8"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="J5A-hy-9hb" userLabel="_1.1f Verification Change Number">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IVn-LE-fmp">
<color key="backgroundColor" red="0.87794482707977295" green="0.87811338901519775" blue="0.87791669368743896" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="56" id="qQe-8g-3LR"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title=" Change Number">
<color key="titleColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="ZUP-dD-a8s" kind="unwind" unwindAction="unwindToChangeNumber:" id="4Dh-Ef-EAM"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="_arrow_button" translatesAutoresizingMaskIntoConstraints="NO" id="rj8-Z7-7mp"/>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="IVn-LE-fmp" firstAttribute="width" secondItem="J5A-hy-9hb" secondAttribute="width" constant="8" id="8Dw-FS-ZwO"/>
<constraint firstAttribute="centerY" secondItem="rj8-Z7-7mp" secondAttribute="centerY" id="9Q9-I2-jzZ"/>
<constraint firstItem="rj8-Z7-7mp" firstAttribute="leading" secondItem="J5A-hy-9hb" secondAttribute="leading" constant="8" id="WOv-B2-Gqu"/>
<constraint firstAttribute="height" constant="57" id="Ymo-ed-7g0"/>
<constraint firstItem="IVn-LE-fmp" firstAttribute="leading" secondItem="J5A-hy-9hb" secondAttribute="leading" id="asD-lu-sVJ"/>
<constraint firstAttribute="trailing" secondItem="IVn-LE-fmp" secondAttribute="trailing" constant="-8" id="evp-Yo-CxG"/>
<constraint firstAttribute="bottom" secondItem="IVn-LE-fmp" secondAttribute="bottom" constant="-2" id="o0O-Dk-h65"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="65n-ug-kaa" userLabel="_1.1e Verification Call Me Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2I5-tm-rMi">
<color key="backgroundColor" red="0.65349096059799194" green="0.75299829244613647" blue="0.99915063381195068" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="57" id="3CX-0k-nDf"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="0.0" minY="1" maxX="0.0" maxY="0.0"/>
<state key="normal" title=" Call Me Instead">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeVoiceAction:" destination="3Uo-Ow-qOD" eventType="touchUpInside" id="YWt-aa-RUW"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(555) 555-5555" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wYz-da-3ZB">
<constraints>
<constraint firstAttribute="width" constant="164" id="ElJ-Jb-M1R"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.23574128746986389" green="0.2357865571975708" blue="0.23573371767997742" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="lFE-KR-9iN">
<constraints>
<constraint firstAttribute="height" constant="20" id="S5y-W0-fAs"/>
<constraint firstAttribute="width" constant="20" id="rFK-EJ-Xgu"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerY" secondItem="wYz-da-3ZB" secondAttribute="centerY" id="21A-bh-r9x"/>
<constraint firstItem="lFE-KR-9iN" firstAttribute="leading" secondItem="2I5-tm-rMi" secondAttribute="leading" constant="149" id="K86-nl-kJL"/>
<constraint firstItem="2I5-tm-rMi" firstAttribute="width" secondItem="65n-ug-kaa" secondAttribute="width" id="TUC-gA-7w2"/>
<constraint firstAttribute="height" constant="57" id="TYj-Qb-QrL"/>
<constraint firstAttribute="centerY" secondItem="2I5-tm-rMi" secondAttribute="centerY" id="VBf-oG-Ad1"/>
<constraint firstAttribute="centerX" secondItem="2I5-tm-rMi" secondAttribute="centerX" id="Zwz-EA-Uv1"/>
<constraint firstAttribute="trailing" secondItem="wYz-da-3ZB" secondAttribute="trailing" constant="27" id="jOv-Cx-5mj"/>
<constraint firstItem="lFE-KR-9iN" firstAttribute="centerY" secondItem="2I5-tm-rMi" secondAttribute="centerY" constant="0.5" id="ovP-12-VEp"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="XXt-2F-6KC" firstAttribute="leading" secondItem="Zgb-Uj-73M" secondAttribute="leadingMargin" constant="-16" id="186-I2-PpT"/>
<constraint firstAttribute="trailingMargin" secondItem="95o-ce-XGu" secondAttribute="trailing" constant="-16" id="1PA-ZM-HLt"/>
<constraint firstAttribute="width" secondItem="lIs-Ck-sAt" secondAttribute="width" id="3UN-Zb-j14"/>
<constraint firstAttribute="centerX" secondItem="lIs-Ck-sAt" secondAttribute="centerX" id="8Vt-pz-DHH"/>
<constraint firstItem="XXt-2F-6KC" firstAttribute="top" secondItem="lIs-Ck-sAt" secondAttribute="bottom" constant="45" id="DLn-mq-TQC"/>
<constraint firstItem="95o-ce-XGu" firstAttribute="top" secondItem="XXt-2F-6KC" secondAttribute="bottom" constant="8" id="J6B-PT-YCI"/>
<constraint firstItem="MHI-1c-yZH" firstAttribute="top" secondItem="65n-ug-kaa" secondAttribute="bottom" constant="55" id="JCm-AV-mvA"/>
<constraint firstItem="65n-ug-kaa" firstAttribute="width" secondItem="Zgb-Uj-73M" secondAttribute="width" id="JXl-Js-EdT"/>
<constraint firstItem="95o-ce-XGu" firstAttribute="leading" secondItem="Zgb-Uj-73M" secondAttribute="leadingMargin" constant="-16" id="SHP-xM-fNk"/>
<constraint firstAttribute="centerX" secondItem="65n-ug-kaa" secondAttribute="centerX" id="V1z-SJ-QA5"/>
<constraint firstAttribute="trailingMargin" secondItem="XXt-2F-6KC" secondAttribute="trailing" constant="-16" id="Yqu-ew-0Ox"/>
<constraint firstItem="UWb-Di-S2f" firstAttribute="top" secondItem="95o-ce-XGu" secondAttribute="bottom" constant="3" id="dJ1-z6-uc7"/>
<constraint firstAttribute="centerX" secondItem="J5A-hy-9hb" secondAttribute="centerX" constant="1" id="dqK-wN-Qqd"/>
<constraint firstAttribute="trailingMargin" secondItem="UWb-Di-S2f" secondAttribute="trailing" constant="-16" id="e8e-kK-ZKM"/>
<constraint firstItem="UWb-Di-S2f" firstAttribute="leading" secondItem="Zgb-Uj-73M" secondAttribute="leadingMargin" constant="-16" id="gln-Vt-qVB"/>
<constraint firstItem="lIs-Ck-sAt" firstAttribute="top" secondItem="OuY-yn-ZQb" secondAttribute="bottom" constant="-20" id="ppb-ts-aZV"/>
<constraint firstItem="MHI-1c-yZH" firstAttribute="top" secondItem="J5A-hy-9hb" secondAttribute="bottom" id="x9N-aq-ABK"/>
<constraint firstItem="J5A-hy-9hb" firstAttribute="width" secondItem="Zgb-Uj-73M" secondAttribute="width" id="zDg-Za-jzf"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="vKt-jE-G1j"/>
<nil key="simulatedTopBarMetrics"/>
<connections>
<outlet property="challengeButton" destination="5Nx-nz-ht7" id="JO8-b7-GHV"/>
<outlet property="challengeTextField" destination="yK6-ad-ihc" id="cnh-li-Z6O"/>
<outlet property="changeNumberButton" destination="IVn-LE-fmp" id="ciO-XU-zhq"/>
<outlet property="headerConstraint" destination="5bj-kr-L4s" id="mCo-eL-dVs"/>
<outlet property="headerLabel" destination="e8Y-At-xEK" id="rFs-ii-khZ"/>
<outlet property="phoneNumberEntered" destination="wYz-da-3ZB" id="3Ah-VX-CXn"/>
<outlet property="requestCallSpinner" destination="lFE-KR-9iN" id="cAe-kr-tgj"/>
<outlet property="requestCodeAgainSpinner" destination="utk-2S-Qc7" id="9W8-ZF-1fI"/>
<outlet property="sendCodeViaSMSAgainButton" destination="9dl-sl-tZN" id="P3C-jR-K09"/>
<outlet property="sendCodeViaVoiceButton" destination="2I5-tm-rMi" id="h8C-UP-pj7"/>
<outlet property="signalLogo" destination="gVg-vn-tFu" id="ORq-vX-wls"/>
<outlet property="submitCodeSpinner" destination="vmS-8s-cvA" id="6Yh-84-o0p"/>
</connections>
</viewController>
<exit id="ZUP-dD-a8s" userLabel="Exit" sceneMemberID="exit"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="WLS-Zq-ncm" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3548" y="-732.72000000000003"/>
</scene>
<!--Signals Navigation Controller-->
<scene sceneID="miN-Ma-3eR">
<objects>
@ -1381,7 +837,7 @@
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6tU-Dy-HQe" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-4372" y="-1537.8599999999999"/>
<point key="canvasLocation" x="-3434" y="-1541"/>
</scene>
<!--Linked Devices-->
<scene sceneID="R59-ey-Ucx">
@ -1396,7 +852,7 @@
<rect key="frame" x="0.0" y="120" width="375" height="72"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="XjV-oU-jSb" id="XqL-QG-IbY">
<frame key="frameInset" width="375" height="72"/>
<frame key="frameInset" width="375" height="71"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Signal on Chrome" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="57o-uV-YOg">
@ -1437,18 +893,18 @@
<rect key="frame" x="0.0" y="192" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="6h2-gg-1C6" id="RKi-c6-pzb">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Link New Device" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="w80-IJ-E6R">
<frame key="frameInset" minX="15" minY="4" width="127" height="20.5"/>
<frame key="frameInset" minX="15" minY="3" width="127" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Scan QR Code" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8ft-2u-wBF">
<frame key="frameInset" minX="15" minY="24.5" width="88" height="16"/>
<frame key="frameInset" minX="15" minY="24" width="88" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1487,7 +943,7 @@
<rect key="frame" x="0.0" y="64" width="375" height="118"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5zF-Ko-9qU" id="gr7-Sm-bcs">
<frame key="frameInset" width="375" height="118"/>
<frame key="frameInset" width="375" height="117"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1 (708) 000-1234" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ipE-BI-sLL">
@ -1526,7 +982,7 @@
<rect key="frame" x="0.0" y="182" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8rk-06-1ZS" id="hqv-P5-du9">
<frame key="frameInset" width="375" height="44"/>
<frame key="frameInset" width="375" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Network Status" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uNq-FV-lwt">
@ -1564,11 +1020,11 @@
<rect key="frame" x="0.0" y="226" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ITG-sW-Zn0" id="vOb-SA-SH2">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Privacy" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="i1f-DT-7rL">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1581,11 +1037,11 @@
<rect key="frame" x="0.0" y="270" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jp5-vZ-AhJ" id="sji-CJ-bhq">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Notifications" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tRQ-1p-6aT">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1598,11 +1054,11 @@
<rect key="frame" x="0.0" y="314" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wZ8-fs-Ylw" id="Ua5-nw-s2z">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Linked Devices" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hrc-lZ-NeA">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1618,11 +1074,11 @@
<rect key="frame" x="0.0" y="358" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Xx7-pz-aLN" id="pMA-vR-8Ae">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Advanced" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dkL-Nz-E6H">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1635,11 +1091,11 @@
<rect key="frame" x="0.0" y="402" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EI4-kQ-MMA" id="czg-5p-aVz">
<frame key="frameInset" width="342" height="44"/>
<frame key="frameInset" width="342" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="About" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="qeN-f1-cIQ">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<frame key="frameInset" minX="15" width="325" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -1656,7 +1112,7 @@
<rect key="frame" x="0.0" y="446" width="375" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="R82-FT-SEA" id="Ok9-fE-WhB">
<frame key="frameInset" width="375" height="100"/>
<frame key="frameInset" width="375" height="99"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Mk-ly-6fq">
@ -1833,7 +1289,7 @@
<rect key="frame" x="0.0" y="22" width="375" height="48"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ld5-sX-pB8" id="EqP-87-4hZ">
<frame key="frameInset" width="375" height="48"/>
<frame key="frameInset" width="375" height="47"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="urb-Me-knG">
@ -1950,11 +1406,11 @@
<rect key="frame" x="0.0" y="62" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="yfF-Jl-bZ1" id="f0v-od-N9K">
<frame key="frameInset" width="375" height="60"/>
<frame key="frameInset" width="375" height="59"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="a4j-OQ-ala">
<frame key="frameInset" minX="15" width="345" height="59.5"/>
<frame key="frameInset" minX="15" width="345" height="59"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -2000,28 +1456,6 @@
</objects>
<point key="canvasLocation" x="-1816" y="-236"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="kfT-eG-hkf">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" navigationBarHidden="YES" id="lIF-0m-2N3" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="l1Z-lc-H46">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="D2L-cq-DaY">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
</toolbar>
<connections>
<segue destination="sL4-Zw-2Og" kind="relationship" relationship="rootViewController" id="zqL-2e-WXU"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="eOz-Mr-Nmp" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-4372" y="-732.72000000000003"/>
</scene>
<!--Device QR Scanner-->
<scene sceneID="f3S-St-vF2">
<objects>
@ -2060,7 +1494,6 @@
</scene>
</scenes>
<resources>
<image name="_arrow_button" width="12" height="23"/>
<image name="btnCamera--white" width="52" height="40"/>
<image name="btnCancel--white" width="44" height="44"/>
<image name="btnGroup--white" width="44" height="44"/>
@ -2072,7 +1505,6 @@
<image name="endcall.png" width="100" height="100"/>
<image name="ic_devices_ios" width="180" height="119"/>
<image name="ic_lock_outline" width="32" height="32"/>
<image name="logoSignal" width="138" height="139"/>
<image name="mute-active" width="80" height="80"/>
<image name="mute-inactive" width="80" height="80"/>
<image name="settings" width="44" height="44"/>
@ -2087,8 +1519,7 @@
<simulatedScreenMetrics key="destination" type="retina4_7.fullscreen"/>
</simulatedMetricsContainer>
<inferredMetricsTieBreakers>
<segue reference="xo7-5J-BJb"/>
<segue reference="wgA-Oo-kKq"/>
<segue reference="tfr-ZV-qWs"/>
<segue reference="E8S-Yc-X7E"/>
</inferredMetricsTieBreakers>
</document>

View File

@ -0,0 +1,593 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="zqr-Ab-axp">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--_1.0 Registration Screen-->
<scene sceneID="mx5-Ld-bVC">
<objects>
<viewController storyboardIdentifier="RegistrationViewController" id="nS2-Vr-sRt" userLabel="_1.0 Registration Screen" customClass="RegistrationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="r20-Uu-fes"/>
<viewControllerLayoutGuide type="bottom" id="VXl-FQ-a8g"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="NJf-bg-N21" userLabel="_1.0 Registration Screen">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xmu-A7-TNZ" userLabel="_1.0a Registration Screen Title">
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your Phone Number" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K0h-3v-ziO">
<constraints>
<constraint firstAttribute="height" constant="29" id="kQ1-1j-ABF"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="0de-rr-b5G"/>
</subviews>
<color key="backgroundColor" red="0.1135657504" green="0.4787300229" blue="0.89595204589999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" secondItem="K0h-3v-ziO" secondAttribute="width" id="4l7-4V-dIx"/>
<constraint firstItem="K0h-3v-ziO" firstAttribute="top" secondItem="0de-rr-b5G" secondAttribute="bottom" constant="8" id="AGh-EW-HI6"/>
<constraint firstAttribute="centerX" secondItem="K0h-3v-ziO" secondAttribute="centerX" constant="-1" id="AIL-Y4-wEG"/>
<constraint firstAttribute="height" constant="245" id="EX0-kF-4ZZ"/>
<constraint firstAttribute="bottom" secondItem="K0h-3v-ziO" secondAttribute="bottom" constant="26" id="GzS-Jj-DiU"/>
<constraint firstAttribute="centerX" secondItem="0de-rr-b5G" secondAttribute="centerX" id="d3o-xW-nyx"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ogW-8F-AvT" userLabel="_1.0b Registration Country Code Selection">
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Lch-qL-C1Y">
<color key="backgroundColor" red="0.75549191240000002" green="0.75563699009999996" blue="0.75546777249999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="B7F-lc-fBJ"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aSz-jb-g2o">
<constraints>
<constraint firstAttribute="width" constant="67" id="2eK-uf-CSO"/>
<constraint firstAttribute="height" constant="26" id="XPQ-5W-mbO"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<state key="normal" title="+1">
<color key="titleColor" red="0.054103322330000002" green="0.45790460710000003" blue="0.9261735082" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="CCL-Zs-hfU" kind="presentation" id="foJ-CL-5wr"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pu7-Ia-adg">
<rect key="contentStretch" x="1" y="0.0" width="1" height="1"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="wO6-Jl-BdE"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<state key="normal" title="Country Code">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="CCL-Zs-hfU" kind="presentation" id="uxC-Up-OyM"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Lch-qL-C1Y" secondAttribute="trailing" id="Gt8-RR-WBc"/>
<constraint firstAttribute="centerY" secondItem="aSz-jb-g2o" secondAttribute="centerY" id="HU4-qW-Gz8"/>
<constraint firstItem="Lch-qL-C1Y" firstAttribute="top" secondItem="ogW-8F-AvT" secondAttribute="top" constant="59" id="R4z-Zx-3tZ"/>
<constraint firstAttribute="trailing" secondItem="Pu7-Ia-adg" secondAttribute="trailing" constant="105" id="Y5T-N5-RQV"/>
<constraint firstItem="Pu7-Ia-adg" firstAttribute="top" secondItem="ogW-8F-AvT" secondAttribute="top" id="bGo-09-tC2"/>
<constraint firstAttribute="trailing" secondItem="aSz-jb-g2o" secondAttribute="trailing" constant="16" id="hlM-OC-LN6"/>
<constraint firstItem="Pu7-Ia-adg" firstAttribute="leading" secondItem="ogW-8F-AvT" secondAttribute="leading" constant="20" id="qu0-ZZ-p0W"/>
<constraint firstAttribute="height" constant="60" id="rfw-FH-ybj"/>
<constraint firstItem="Lch-qL-C1Y" firstAttribute="leading" secondItem="ogW-8F-AvT" secondAttribute="leading" id="s5Y-V5-Wab"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rrP-cR-EdR" userLabel="_1.0c Registration Phone Number Input">
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dl2-b7-xdO">
<color key="backgroundColor" red="0.75559091570000003" green="0.75556838510000002" blue="0.75558114050000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="NYr-pV-kmN"/>
</constraints>
</view>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Enter Number" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="3dc-W2-Cct">
<constraints>
<constraint firstAttribute="height" constant="26" id="lFp-Li-YIs"/>
<constraint firstAttribute="width" constant="176" id="saS-cJ-AqF"/>
</constraints>
<color key="textColor" red="0.23574128750000001" green="0.2357865572" blue="0.23573371770000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<textInputTraits key="textInputTraits" keyboardType="phonePad" keyboardAppearance="light"/>
</textField>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OHo-Bz-J6X">
<constraints>
<constraint firstAttribute="height" constant="26" id="FJs-Tn-tgw"/>
<constraint firstAttribute="width" constant="152" id="FXC-xX-QzS"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<state key="normal" title="Phone Number">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="OHo-Bz-J6X" firstAttribute="leading" secondItem="rrP-cR-EdR" secondAttribute="leading" constant="20" id="AYJ-bM-qNc"/>
<constraint firstItem="OHo-Bz-J6X" firstAttribute="top" secondItem="rrP-cR-EdR" secondAttribute="top" constant="18" id="CD4-Am-3dE"/>
<constraint firstAttribute="height" constant="61" id="JzF-Pn-EFj"/>
<constraint firstAttribute="trailing" secondItem="Dl2-b7-xdO" secondAttribute="trailing" constant="-40" id="Tec-mV-MQl"/>
<constraint firstItem="3dc-W2-Cct" firstAttribute="top" secondItem="rrP-cR-EdR" secondAttribute="top" constant="19" id="dRt-yw-0Td"/>
<constraint firstAttribute="trailing" secondItem="3dc-W2-Cct" secondAttribute="trailing" constant="16" id="jqT-TF-omH"/>
<constraint firstItem="Dl2-b7-xdO" firstAttribute="leading" secondItem="rrP-cR-EdR" secondAttribute="leading" id="nsi-Cg-As6"/>
<constraint firstItem="Dl2-b7-xdO" firstAttribute="top" secondItem="rrP-cR-EdR" secondAttribute="top" constant="59" id="xE3-Lu-01P"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iDP-Me-eCf" userLabel="_1.0d Registration Verification Code Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mtj-nl-ohU">
<color key="backgroundColor" red="0.08213712275" green="0.4684380293" blue="0.91112053390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="47" id="Tgf-rp-YCy"/>
<constraint firstAttribute="height" constant="47" id="pNQ-IE-Fz9"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
<state key="normal" title="Verify This Device">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeAction:" destination="nS2-Vr-sRt" eventType="touchUpInside" id="fJr-gJ-4EN"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="DBZ-d0-eAi">
<constraints>
<constraint firstAttribute="height" constant="20" id="wJ6-5U-WEn"/>
<constraint firstAttribute="width" constant="20" id="zIf-LA-Z5C"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="mtj-nl-ohU" firstAttribute="top" secondItem="iDP-Me-eCf" secondAttribute="top" constant="1" id="Dff-xZ-xvv"/>
<constraint firstItem="mtj-nl-ohU" firstAttribute="leading" secondItem="iDP-Me-eCf" secondAttribute="leading" constant="30" id="aBh-6a-w1n"/>
<constraint firstItem="DBZ-d0-eAi" firstAttribute="top" secondItem="mtj-nl-ohU" secondAttribute="top" constant="14" id="hLQ-d0-2nv"/>
<constraint firstItem="DBZ-d0-eAi" firstAttribute="trailing" secondItem="mtj-nl-ohU" secondAttribute="trailing" constant="-20" id="kyH-um-7rx"/>
<constraint firstAttribute="height" constant="47" id="oYk-Aj-EDD"/>
<constraint firstAttribute="trailing" secondItem="mtj-nl-ohU" secondAttribute="trailing" constant="30" id="qWP-JR-pdn"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="ogW-8F-AvT" secondAttribute="trailing" constant="-16" id="52r-uL-fTy"/>
<constraint firstAttribute="centerX" secondItem="xmu-A7-TNZ" secondAttribute="centerX" id="BqA-cq-dwf"/>
<constraint firstItem="ogW-8F-AvT" firstAttribute="leading" secondItem="NJf-bg-N21" secondAttribute="leadingMargin" constant="-16" id="EPx-WT-zWo"/>
<constraint firstItem="xmu-A7-TNZ" firstAttribute="width" secondItem="NJf-bg-N21" secondAttribute="width" id="FGC-aY-f9A"/>
<constraint firstItem="rrP-cR-EdR" firstAttribute="leading" secondItem="NJf-bg-N21" secondAttribute="leadingMargin" constant="-16" id="K4z-MB-kzs"/>
<constraint firstAttribute="trailingMargin" secondItem="rrP-cR-EdR" secondAttribute="trailing" constant="-16" id="Lwy-E4-8Ee"/>
<constraint firstItem="xmu-A7-TNZ" firstAttribute="top" secondItem="r20-Uu-fes" secondAttribute="bottom" constant="-20" id="Otb-w3-TYT"/>
<constraint firstItem="ogW-8F-AvT" firstAttribute="top" secondItem="xmu-A7-TNZ" secondAttribute="bottom" id="ZjB-A5-R0v"/>
<constraint firstItem="iDP-Me-eCf" firstAttribute="leading" secondItem="NJf-bg-N21" secondAttribute="leadingMargin" constant="-16" id="aa4-CR-ieG"/>
<constraint firstItem="rrP-cR-EdR" firstAttribute="top" secondItem="ogW-8F-AvT" secondAttribute="bottom" id="srb-kk-5P5"/>
<constraint firstAttribute="trailingMargin" secondItem="iDP-Me-eCf" secondAttribute="trailing" constant="-16" id="syq-Ef-9Lq"/>
<constraint firstItem="iDP-Me-eCf" firstAttribute="top" secondItem="rrP-cR-EdR" secondAttribute="bottom" constant="9" id="uX8-hI-UyT"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="PhN-sR-LcA"/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
<nil key="simulatedTopBarMetrics"/>
<connections>
<outlet property="countryCodeButton" destination="aSz-jb-g2o" id="HAe-2D-BxF"/>
<outlet property="countryNameButton" destination="Pu7-Ia-adg" id="PFU-m2-gzV"/>
<outlet property="headerHeightConstraint" destination="EX0-kF-4ZZ" id="e8J-On-rOg"/>
<outlet property="phoneNumberButton" destination="OHo-Bz-J6X" id="V1H-FP-hcY"/>
<outlet property="phoneNumberTextField" destination="3dc-W2-Cct" id="xWc-E5-zL3"/>
<outlet property="sendCodeButton" destination="mtj-nl-ohU" id="byR-sB-ZeM"/>
<outlet property="signalLogo" destination="0de-rr-b5G" id="3G1-Yh-gAM"/>
<outlet property="spinnerView" destination="DBZ-d0-eAi" id="rbd-C8-3t6"/>
<outlet property="titleLabel" destination="K0h-3v-ziO" id="xui-9i-8Sp"/>
<segue destination="vAf-74-zQH" kind="show" identifier="codeSent" id="Oue-D5-f7y"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="YTE-zH-eXO" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-4663" y="-735"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="CXh-B2-B5s">
<objects>
<navigationController id="CCL-Zs-hfU" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="cF0-06-4sO">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" red="0.08213712275" green="0.4684380293" blue="0.91112053390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<connections>
<segue destination="Z2i-u6-bhY" kind="relationship" relationship="rootViewController" id="MJ5-IX-jSb"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="m2Q-Yk-UFa" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-4663" y="118"/>
</scene>
<!--_2.0_1.0__1 Country Code Modal-->
<scene sceneID="kX2-KQ-Haq">
<objects>
<tableViewController storyboardIdentifier="CountryCodeViewController" id="Z2i-u6-bhY" userLabel="_2.0_1.0__1 Country Code Modal" customClass="CountryCodeViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="HIm-Hc-yjX" userLabel="_1.0__1 Country Code Table">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<searchBar key="tableHeaderView" contentMode="redraw" id="CMs-3a-1tn" userLabel="__1a Search Bar">
<rect key="frame" x="0.0" y="64" width="375" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits"/>
<connections>
<outlet property="delegate" destination="Z2i-u6-bhY" id="vEf-Fh-V9X"/>
</connections>
</searchBar>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CountryCodeTableViewCell" id="LFg-KJ-GnQ" userLabel="__1b Country Code Table" customClass="CountryCodeTableViewCell">
<rect key="frame" x="0.0" y="130" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="LFg-KJ-GnQ" id="o6y-AP-QLT" userLabel="Country Code Table Row">
<frame key="frameInset" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="United states" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eyx-0e-8jI">
<constraints>
<constraint firstAttribute="width" constant="244" id="n1j-cy-UCc"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="2" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="+1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EEE-5L-cqs">
<constraints>
<constraint firstAttribute="width" constant="64" id="Esx-e5-KEm"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<color key="textColor" red="0.4266758859" green="0.42666310070000002" blue="0.42667034269999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="eyx-0e-8jI" firstAttribute="leading" secondItem="o6y-AP-QLT" secondAttribute="leadingMargin" constant="12" id="3e1-Ho-Lkh"/>
<constraint firstAttribute="centerY" secondItem="eyx-0e-8jI" secondAttribute="centerY" id="9tf-zE-uTh"/>
<constraint firstAttribute="trailingMargin" secondItem="EEE-5L-cqs" secondAttribute="trailing" constant="11" id="VWY-K4-mnQ"/>
<constraint firstAttribute="centerY" secondItem="EEE-5L-cqs" secondAttribute="centerY" id="xkZ-7a-4si"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="countryCodeLabel" destination="EEE-5L-cqs" id="l5s-J2-hEb"/>
<outlet property="countryNameLabel" destination="eyx-0e-8jI" id="FVB-VB-L0Y"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="Z2i-u6-bhY" id="rHA-cX-cjx"/>
<outlet property="delegate" destination="Z2i-u6-bhY" id="XPn-SJ-wjB"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Select Country Code" id="Q6t-Dx-qGA" userLabel="_1.0__1c Navigation Bar">
<barButtonItem key="leftBarButtonItem" image="btnCancel--white" id="upu-bg-cQC">
<connections>
<segue destination="dCz-q4-kx5" kind="unwind" unwindAction="unwindToCountryCodeSelectionCancelled:" id="rAG-7g-91h"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="countryCodeTableView" destination="HIm-Hc-yjX" id="SJ0-1f-5bx"/>
<outlet property="searchBar" destination="CMs-3a-1tn" id="OZf-gj-MFu"/>
<outlet property="searchDisplayController" destination="b82-X1-yzZ" id="tc5-Ii-aAN"/>
<segue destination="dCz-q4-kx5" kind="unwind" identifier="UnwindToCountryCodeWasSelectedSegue" unwindAction="unwindToCountryCodeWasSelected:" id="grw-Tg-ALb"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="eQ6-CW-FOy" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="dCz-q4-kx5" userLabel="Exit" sceneMemberID="exit"/>
<searchDisplayController id="b82-X1-yzZ">
<connections>
<outlet property="delegate" destination="Z2i-u6-bhY" id="rO2-da-1gE"/>
<outlet property="searchContentsController" destination="Z2i-u6-bhY" id="m7R-H5-bMY"/>
<outlet property="searchResultsDataSource" destination="Z2i-u6-bhY" id="JmH-Rd-hgI"/>
<outlet property="searchResultsDelegate" destination="Z2i-u6-bhY" id="kmD-Pu-fbT"/>
</connections>
</searchDisplayController>
<navigationItem title="Title" id="DLP-7z-aG1"/>
</objects>
<point key="canvasLocation" x="-3780" y="118"/>
</scene>
<!--_1.1 Verification Screen-->
<scene sceneID="9FI-Mi-3YV">
<objects>
<viewController storyboardIdentifier="CodeVerificationViewController" id="vAf-74-zQH" userLabel="_1.1 Verification Screen" customClass="CodeVerificationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="FTb-jf-cJ8"/>
<viewControllerLayoutGuide type="bottom" id="bCG-HQ-yTo"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="psv-5C-Zla" userLabel="_1.1 Verification Screen">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X6Y-tl-Cgw" userLabel="_1.1a Validation Screen Title">
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Verification" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ARw-Wq-shF">
<constraints>
<constraint firstAttribute="height" constant="29" id="k8W-ot-RTD"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="Yql-X5-USw"/>
</subviews>
<color key="backgroundColor" red="0.1135657504" green="0.4787300229" blue="0.89595204589999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="ARw-Wq-shF" firstAttribute="top" secondItem="Yql-X5-USw" secondAttribute="bottom" constant="8" id="3eF-XL-6Lr"/>
<constraint firstAttribute="centerX" secondItem="Yql-X5-USw" secondAttribute="centerX" constant="-1" id="HKm-Rb-Dkv"/>
<constraint firstAttribute="bottom" secondItem="ARw-Wq-shF" secondAttribute="bottom" constant="25" id="IjJ-NL-ckF"/>
<constraint firstAttribute="width" secondItem="ARw-Wq-shF" secondAttribute="width" id="TVo-yg-YPd"/>
<constraint firstAttribute="centerX" secondItem="ARw-Wq-shF" secondAttribute="centerX" constant="-1" id="ihp-cT-EIU"/>
<constraint firstAttribute="height" constant="245" id="nNa-2d-2TY" userLabel="Height - (245) - _1.1 Registration Screen Title"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YJG-aq-61Z" userLabel="_1.1b Verification Code Input">
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Verification Code" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="1Tc-6s-gy4">
<constraints>
<constraint firstAttribute="width" constant="401" id="UJE-wv-0hP"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="21"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad" keyboardAppearance="alert"/>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Geg-HS-jcj">
<color key="backgroundColor" red="0.75559091570000003" green="0.75556838510000002" blue="0.75558114050000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Z6p-lf-JBI"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Geg-HS-jcj" firstAttribute="top" secondItem="YJG-aq-61Z" secondAttribute="top" constant="26" id="9pO-wM-BCT"/>
<constraint firstAttribute="trailing" secondItem="Geg-HS-jcj" secondAttribute="trailing" constant="36" id="CRZ-0F-pew"/>
<constraint firstAttribute="centerX" secondItem="1Tc-6s-gy4" secondAttribute="centerX" constant="-0.5" id="Hzf-g1-PJP"/>
<constraint firstItem="Geg-HS-jcj" firstAttribute="leading" secondItem="YJG-aq-61Z" secondAttribute="leading" constant="36" id="IQ7-Ym-dVl"/>
<constraint firstAttribute="height" secondItem="1Tc-6s-gy4" secondAttribute="height" id="K1W-tg-cKf"/>
<constraint firstItem="1Tc-6s-gy4" firstAttribute="top" secondItem="YJG-aq-61Z" secondAttribute="top" id="QkZ-mg-2hA"/>
<constraint firstAttribute="height" constant="32" id="dHC-41-kby"/>
<constraint firstAttribute="centerX" secondItem="Geg-HS-jcj" secondAttribute="centerX" id="f1A-a1-Jps"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kGf-fT-Xa9" userLabel="_1.1c Verification Verify Code Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="271-cA-ife">
<color key="backgroundColor" red="0.08213712275" green="0.4684380293" blue="0.91112053390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="47" id="SkX-P2-Wf2"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<state key="normal" title="Submit Verification Code">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="verifyChallengeAction:" destination="vAf-74-zQH" eventType="touchUpInside" id="8eQ-d4-Uqw"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="v7i-Ei-OY8">
<constraints>
<constraint firstAttribute="height" constant="20" id="dMD-1H-5LN"/>
<constraint firstAttribute="width" constant="20" id="uY4-vq-35w"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="47" id="HT2-1F-wht"/>
<constraint firstItem="v7i-Ei-OY8" firstAttribute="top" secondItem="271-cA-ife" secondAttribute="top" constant="14" id="Qvq-9G-l8v"/>
<constraint firstItem="v7i-Ei-OY8" firstAttribute="trailing" secondItem="271-cA-ife" secondAttribute="trailing" constant="-15" id="Zti-hR-cZD"/>
<constraint firstAttribute="trailing" secondItem="271-cA-ife" secondAttribute="trailing" constant="36" id="azZ-uj-VZt"/>
<constraint firstItem="271-cA-ife" firstAttribute="top" secondItem="kGf-fT-Xa9" secondAttribute="top" id="eKO-P7-DMK"/>
<constraint firstItem="271-cA-ife" firstAttribute="leading" secondItem="kGf-fT-Xa9" secondAttribute="leading" constant="36" id="xsH-Qd-vxD"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZPv-Ds-6PW" userLabel="_1.1d Verification Send Again Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oZ5-7X-Fql">
<constraints>
<constraint firstAttribute="height" constant="47" id="y8d-km-hod"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<state key="normal" title="Request Code Again">
<color key="titleColor" red="0.081759713590000005" green="0.4691397846" blue="0.91040575499999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeSMSAction:" destination="vAf-74-zQH" eventType="touchUpInside" id="Vax-JY-HKt"/>
</connections>
</button>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="6DZ-uI-Flr">
<constraints>
<constraint firstAttribute="height" constant="20" id="Kco-ht-1A6"/>
<constraint firstAttribute="width" constant="20" id="orp-ul-VMK"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="oZ5-7X-Fql" firstAttribute="leading" secondItem="ZPv-Ds-6PW" secondAttribute="leading" constant="36" id="LD6-Y9-Ys5"/>
<constraint firstItem="6DZ-uI-Flr" firstAttribute="trailing" secondItem="oZ5-7X-Fql" secondAttribute="trailing" constant="-14" id="Ltw-nJ-FBb"/>
<constraint firstItem="oZ5-7X-Fql" firstAttribute="top" secondItem="ZPv-Ds-6PW" secondAttribute="top" id="eBX-XI-dZ5"/>
<constraint firstAttribute="trailing" secondItem="oZ5-7X-Fql" secondAttribute="trailing" constant="36" id="iyf-9e-EoT"/>
<constraint firstItem="6DZ-uI-Flr" firstAttribute="top" secondItem="ZPv-Ds-6PW" secondAttribute="top" constant="14" id="mfM-gm-jW7"/>
<constraint firstAttribute="height" constant="47" id="qef-31-NSZ"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RIh-Jf-Ksm" userLabel="_1.1f Verification Change Number">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9I1-dc-HZS">
<color key="backgroundColor" red="0.87794482709999999" green="0.87811338900000002" blue="0.87791669370000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="56" id="NnD-Zb-1Nb"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title=" Change Number">
<color key="titleColor" red="0.66666666669999997" green="0.66666666669999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<segue destination="q2h-3P-dah" kind="unwind" unwindAction="unwindToChangeNumber:" id="IyO-5M-A8w"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="_arrow_button" translatesAutoresizingMaskIntoConstraints="NO" id="q3j-RG-yf8"/>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="9I1-dc-HZS" firstAttribute="width" secondItem="RIh-Jf-Ksm" secondAttribute="width" constant="8" id="0R1-MQ-iur"/>
<constraint firstAttribute="height" constant="57" id="C0V-TQ-X11"/>
<constraint firstItem="9I1-dc-HZS" firstAttribute="leading" secondItem="RIh-Jf-Ksm" secondAttribute="leading" id="Nbq-zR-2Vy"/>
<constraint firstItem="q3j-RG-yf8" firstAttribute="leading" secondItem="RIh-Jf-Ksm" secondAttribute="leading" constant="8" id="XVz-Q3-6sf"/>
<constraint firstAttribute="centerY" secondItem="q3j-RG-yf8" secondAttribute="centerY" id="d9k-Uv-kN1"/>
<constraint firstAttribute="trailing" secondItem="9I1-dc-HZS" secondAttribute="trailing" constant="-8" id="nmf-dx-koB"/>
<constraint firstAttribute="bottom" secondItem="9I1-dc-HZS" secondAttribute="bottom" constant="-2" id="yCa-Uj-O22"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fB9-73-vmG" userLabel="_1.1e Verification Call Me Button">
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PCA-qm-tfG">
<color key="backgroundColor" red="0.6534909606" green="0.75299829240000005" blue="0.99915063380000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="57" id="Ybh-4m-PKB"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="0.0" minY="1" maxX="0.0" maxY="0.0"/>
<state key="normal" title=" Call Me Instead">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="sendCodeVoiceAction:" destination="vAf-74-zQH" eventType="touchUpInside" id="g3n-Fx-vmT"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(555) 555-5555" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RQO-ap-IfU">
<constraints>
<constraint firstAttribute="width" constant="164" id="aAa-XO-3vj"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.23574128750000001" green="0.2357865572" blue="0.23573371770000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="oGX-bv-Nfu">
<constraints>
<constraint firstAttribute="height" constant="20" id="7Mu-pr-9bR"/>
<constraint firstAttribute="width" constant="20" id="wXe-eH-lNb"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="PCA-qm-tfG" secondAttribute="centerX" id="5UD-Cp-LFZ"/>
<constraint firstItem="PCA-qm-tfG" firstAttribute="width" secondItem="fB9-73-vmG" secondAttribute="width" id="5Vq-bx-OAS"/>
<constraint firstItem="oGX-bv-Nfu" firstAttribute="leading" secondItem="PCA-qm-tfG" secondAttribute="leading" constant="149" id="GoE-Yy-Cxd"/>
<constraint firstAttribute="centerY" secondItem="PCA-qm-tfG" secondAttribute="centerY" id="Q4D-d0-E4R"/>
<constraint firstAttribute="centerY" secondItem="RQO-ap-IfU" secondAttribute="centerY" id="QFq-1a-Bsx"/>
<constraint firstAttribute="trailing" secondItem="RQO-ap-IfU" secondAttribute="trailing" constant="27" id="Ymg-OD-cqz"/>
<constraint firstItem="oGX-bv-Nfu" firstAttribute="centerY" secondItem="PCA-qm-tfG" secondAttribute="centerY" constant="0.5" id="vpn-oi-l2A"/>
<constraint firstAttribute="height" constant="57" id="wTr-g0-DlL"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="ZPv-Ds-6PW" secondAttribute="trailing" constant="-16" id="73a-MW-yne"/>
<constraint firstAttribute="trailingMargin" secondItem="kGf-fT-Xa9" secondAttribute="trailing" constant="-16" id="8B2-wI-hyc"/>
<constraint firstAttribute="width" secondItem="X6Y-tl-Cgw" secondAttribute="width" id="8bE-il-HeC"/>
<constraint firstItem="ZPv-Ds-6PW" firstAttribute="leading" secondItem="psv-5C-Zla" secondAttribute="leadingMargin" constant="-16" id="8tQ-bH-Ofx"/>
<constraint firstItem="fB9-73-vmG" firstAttribute="width" secondItem="psv-5C-Zla" secondAttribute="width" id="Fpf-eA-723"/>
<constraint firstItem="RIh-Jf-Ksm" firstAttribute="width" secondItem="psv-5C-Zla" secondAttribute="width" id="JqZ-V3-U9S"/>
<constraint firstItem="bCG-HQ-yTo" firstAttribute="top" secondItem="fB9-73-vmG" secondAttribute="bottom" constant="55" id="Rai-zy-BWp"/>
<constraint firstItem="ZPv-Ds-6PW" firstAttribute="top" secondItem="kGf-fT-Xa9" secondAttribute="bottom" constant="3" id="Vg4-ED-Tfd"/>
<constraint firstItem="bCG-HQ-yTo" firstAttribute="top" secondItem="RIh-Jf-Ksm" secondAttribute="bottom" id="Vqs-Kv-skP"/>
<constraint firstItem="kGf-fT-Xa9" firstAttribute="leading" secondItem="psv-5C-Zla" secondAttribute="leadingMargin" constant="-16" id="d09-KR-EtL"/>
<constraint firstAttribute="centerX" secondItem="X6Y-tl-Cgw" secondAttribute="centerX" id="dxr-yW-gjo"/>
<constraint firstItem="kGf-fT-Xa9" firstAttribute="top" secondItem="YJG-aq-61Z" secondAttribute="bottom" constant="8" id="gWq-ll-Ur2"/>
<constraint firstAttribute="centerX" secondItem="fB9-73-vmG" secondAttribute="centerX" id="hbs-so-xXl"/>
<constraint firstAttribute="trailingMargin" secondItem="YJG-aq-61Z" secondAttribute="trailing" constant="-16" id="qLY-R2-kar"/>
<constraint firstItem="YJG-aq-61Z" firstAttribute="leading" secondItem="psv-5C-Zla" secondAttribute="leadingMargin" constant="-16" id="qbs-la-idW"/>
<constraint firstItem="X6Y-tl-Cgw" firstAttribute="top" secondItem="FTb-jf-cJ8" secondAttribute="bottom" constant="-20" id="rhk-bp-Fcp"/>
<constraint firstAttribute="centerX" secondItem="RIh-Jf-Ksm" secondAttribute="centerX" constant="1" id="yJm-4X-xyb"/>
<constraint firstItem="YJG-aq-61Z" firstAttribute="top" secondItem="X6Y-tl-Cgw" secondAttribute="bottom" constant="45" id="z2c-9h-ANc"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="KvQ-qd-ysw"/>
<nil key="simulatedTopBarMetrics"/>
<connections>
<outlet property="challengeButton" destination="271-cA-ife" id="C8B-xI-hT8"/>
<outlet property="challengeTextField" destination="1Tc-6s-gy4" id="JGC-fC-dC1"/>
<outlet property="changeNumberButton" destination="9I1-dc-HZS" id="IpJ-m0-1Q4"/>
<outlet property="headerConstraint" destination="nNa-2d-2TY" id="emq-Ub-aWV"/>
<outlet property="headerLabel" destination="ARw-Wq-shF" id="DKK-ZU-l6m"/>
<outlet property="phoneNumberEntered" destination="RQO-ap-IfU" id="cp9-aW-BxL"/>
<outlet property="requestCallSpinner" destination="oGX-bv-Nfu" id="o1h-SH-RL4"/>
<outlet property="requestCodeAgainSpinner" destination="6DZ-uI-Flr" id="8oS-y6-cZU"/>
<outlet property="sendCodeViaSMSAgainButton" destination="oZ5-7X-Fql" id="Kqf-62-oHh"/>
<outlet property="sendCodeViaVoiceButton" destination="PCA-qm-tfG" id="iDq-eo-lBl"/>
<outlet property="signalLogo" destination="Yql-X5-USw" id="IWh-Uo-sHf"/>
<outlet property="submitCodeSpinner" destination="v7i-Ei-OY8" id="Kmb-V5-efV"/>
<segue destination="ZlQ-iw-Vxb" kind="presentation" identifier="CompletedRegistration" modalPresentationStyle="fullScreen" modalTransitionStyle="crossDissolve" id="Hry-60-bHY"/>
</connections>
</viewController>
<exit id="q2h-3P-dah" userLabel="Exit" sceneMemberID="exit"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="uR6-Tv-iw7" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3780" y="-735"/>
</scene>
<!--Main-->
<scene sceneID="sjs-Ns-GrM">
<objects>
<viewControllerPlaceholder storyboardName="Main" id="ZlQ-iw-Vxb" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="nhi-5D-Zp3" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3149" y="-736"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="WHz-EP-SUz">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" navigationBarHidden="YES" id="zqr-Ab-axp" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Aon-Yn-49y">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="Axh-eu-RXJ">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
</toolbar>
<connections>
<segue destination="nS2-Vr-sRt" kind="relationship" relationship="rootViewController" id="Sw7-Sg-eg7"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="tQU-cc-dJl" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-5502" y="-735"/>
</scene>
</scenes>
<resources>
<image name="_arrow_button" width="12" height="23"/>
<image name="btnCancel--white" width="44" height="44"/>
<image name="logoSignal" width="138" height="139"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="uxC-Up-OyM"/>
</inferredMetricsTieBreakers>
</document>

View File

@ -1,6 +1,6 @@
#import "AudioPacker.h"
#import "DesiredBufferDepthController.h"
#import "PreferencesUtil.h"
#import "AudioPacker.h"
#import "PropertyListPreferences.h"
#import "Util.h"
#define MAX_DESIRED_FRAME_DELAY 12

View File

@ -6,16 +6,16 @@
// Copyright © 2015 Open Whisper Systems. All rights reserved.
//
#import "NotificationsManager.h"
#import "Environment.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import <AudioToolbox/AudioServices.h>
#import <SignalServiceKit/TSCall.h>
#import <SignalServiceKit/TSContactThread.h>
#import <SignalServiceKit/TSErrorMessage.h>
#import <SignalServiceKit/TSIncomingMessage.h>
#import <SignalServiceKit/TextSecureKitEnv.h>
#import "Environment.h"
#import "NotificationsManager.h"
#import "PreferencesUtil.h"
#import "PushManager.h"
@interface NotificationsManager ()

View File

@ -1,50 +0,0 @@
#import "PropertyListPreferences.h"
typedef NS_ENUM(NSUInteger, NotificationType) {
NotificationNoNameNoPreview,
NotificationNameNoPreview,
NotificationNamePreview,
};
typedef NS_ENUM(NSUInteger, TSImageQuality) {
TSImageQualityUncropped = 1,
TSImageQualityHigh = 2,
TSImageQualityMedium = 3,
TSImageQualityLow = 4
};
@class PhoneNumber;
@interface PropertyListPreferences (PropertyUtil)
- (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth;
- (void)setCachedDesiredBufferDepth:(double)value;
- (BOOL)getHasSentAMessage;
- (void)setHasSentAMessage:(BOOL)enabled;
- (BOOL)getHasArchivedAMessage;
- (void)setHasArchivedAMessage:(BOOL)enabled;
- (BOOL)loggingIsEnabled;
- (void)setLoggingEnabled:(BOOL)flag;
- (BOOL)screenSecurityIsEnabled;
- (void)setScreenSecurity:(BOOL)flag;
- (NotificationType)notificationPreviewType;
- (void)setNotificationPreviewType:(NotificationType)type;
- (NSString *)nameForNotificationPreviewType:(NotificationType)notificationType;
- (BOOL)soundInForeground;
- (void)setSoundInForeground:(BOOL)enabled;
- (BOOL)hasRegisteredVOIPPush;
- (void)setHasRegisteredVOIPPush:(BOOL)enabled;
- (TSImageQuality)imageUploadQuality;
- (NSString *)lastRanVersion;
- (NSString *)setAndGetCurrentVersion;
@end

View File

@ -1,152 +0,0 @@
#import "Constraints.h"
#import "PreferencesUtil.h"
#define CALL_STREAM_DES_BUFFER_LEVEL_KEY @"CallStreamDesiredBufferLevel"
#define DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL 0.5
#define SCREEN_SECURITY_KEY @"Screen Security Key"
#define DEBUG_IS_ENABLED_KEY @"Debugging Log Enabled Key"
#define NOTIFICATION_PREVIEW_TYPE_KEY @"Notification Preview Type Key"
#define HAS_SENT_A_MESSAGE_KEY @"User has sent a message" // TODO remove?
#define HAS_ARCHIVED_A_MESSAGE_KEY @"User archived a message" // TODO remove?
#define kSignalVersionKey @"SignalUpdateVersionKey"
#define PLAY_SOUND_IN_FOREGROUND_KEY @"NotificationSoundInForeground"
#define HAS_REGISTERED_VOIP_PUSH @"VOIPPushEnabled"
@implementation PropertyListPreferences (PropertyUtil)
- (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth {
id v = [self tryGetValueForKey:CALL_STREAM_DES_BUFFER_LEVEL_KEY];
if (v == nil)
return DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL;
return [v doubleValue];
}
- (void)setCachedDesiredBufferDepth:(double)value {
ows_require(value >= 0);
[self setValueForKey:CALL_STREAM_DES_BUFFER_LEVEL_KEY toValue:@(value)];
}
- (BOOL)loggingIsEnabled {
NSNumber *preference = [self tryGetValueForKey:DEBUG_IS_ENABLED_KEY];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (BOOL)screenSecurityIsEnabled
{
NSNumber *preference = [self tryGetValueForKey:SCREEN_SECURITY_KEY];
return preference ? [preference boolValue] : YES;
}
- (BOOL)getHasSentAMessage {
NSNumber *preference = [self tryGetValueForKey:HAS_SENT_A_MESSAGE_KEY];
if (preference) {
return [preference boolValue];
} else {
return NO;
}
}
- (BOOL)getHasArchivedAMessage {
NSNumber *preference = [self tryGetValueForKey:HAS_ARCHIVED_A_MESSAGE_KEY];
if (preference) {
return [preference boolValue];
} else {
return NO;
}
}
- (BOOL)hasRegisteredVOIPPush {
NSNumber *preference = [self tryGetValueForKey:HAS_REGISTERED_VOIP_PUSH];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (TSImageQuality)imageUploadQuality {
// always return average image quality
return TSImageQualityMedium;
}
- (void)setScreenSecurity:(BOOL)flag
{
[self setValueForKey:SCREEN_SECURITY_KEY toValue:@(flag)];
}
- (void)setHasRegisteredVOIPPush:(BOOL)enabled {
[self setValueForKey:HAS_REGISTERED_VOIP_PUSH toValue:@(enabled)];
}
- (void)setLoggingEnabled:(BOOL)flag {
[self setValueForKey:DEBUG_IS_ENABLED_KEY toValue:@(flag)];
}
- (NSString *)lastRanVersion {
return [NSUserDefaults.standardUserDefaults objectForKey:kSignalVersionKey];
}
- (void)setHasSentAMessage:(BOOL)enabled {
[self setValueForKey:HAS_SENT_A_MESSAGE_KEY toValue:@(enabled)];
}
- (void)setHasArchivedAMessage:(BOOL)enabled {
[self setValueForKey:HAS_ARCHIVED_A_MESSAGE_KEY toValue:@(enabled)];
}
- (NSString *)setAndGetCurrentVersion {
NSString *currentVersion =
[NSString stringWithFormat:@"%@", NSBundle.mainBundle.infoDictionary[@"CFBundleVersion"]];
[NSUserDefaults.standardUserDefaults setObject:currentVersion forKey:kSignalVersionKey];
[NSUserDefaults.standardUserDefaults synchronize];
return currentVersion;
}
#pragma mark Notification Preferences
- (BOOL)soundInForeground {
NSNumber *preference = [self tryGetValueForKey:PLAY_SOUND_IN_FOREGROUND_KEY];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (void)setSoundInForeground:(BOOL)enabled {
[self setValueForKey:PLAY_SOUND_IN_FOREGROUND_KEY toValue:@(enabled)];
}
- (void)setNotificationPreviewType:(NotificationType)type {
[self setValueForKey:NOTIFICATION_PREVIEW_TYPE_KEY toValue:@(type)];
}
- (NotificationType)notificationPreviewType {
NSNumber *preference = [self tryGetValueForKey:NOTIFICATION_PREVIEW_TYPE_KEY];
if (preference) {
return [preference unsignedIntegerValue];
} else {
return NotificationNamePreview;
}
}
- (NSString *)nameForNotificationPreviewType:(NotificationType)notificationType {
switch (notificationType) {
case NotificationNamePreview:
return NSLocalizedString(@"NOTIFICATIONS_SENDER_AND_MESSAGE", nil);
case NotificationNameNoPreview:
return NSLocalizedString(@"NOTIFICATIONS_SENDER_ONLY", nil);
case NotificationNoNameNoPreview:
return NSLocalizedString(@"NOTIFICATIONS_NONE", nil);
default:
DDLogWarn(@"Undefined NotificationType in Settings");
return @"";
}
}
@end

View File

@ -1,7 +1,66 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, NotificationType) {
NotificationNoNameNoPreview,
NotificationNameNoPreview,
NotificationNamePreview,
};
typedef NS_ENUM(NSUInteger, TSImageQuality) {
TSImageQualityUncropped = 1,
TSImageQualityHigh = 2,
TSImageQualityMedium = 3,
TSImageQualityLow = 4
};
@interface PropertyListPreferences : NSObject
- (id)tryGetValueForKey:(NSString *)key;
- (void)setValueForKey:(NSString *)key toValue:(id)value;
#pragma mark - Helpers
- (nullable id)tryGetValueForKey:(NSString *)key;
- (void)setValueForKey:(NSString *)key toValue:(nullable id)value;
- (void)clear;
#pragma mark - Specific Preferences
- (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth;
- (void)setCachedDesiredBufferDepth:(double)value;
- (BOOL)getHasSentAMessage;
- (void)setHasSentAMessage:(BOOL)enabled;
- (BOOL)getHasArchivedAMessage;
- (void)setHasArchivedAMessage:(BOOL)enabled;
- (BOOL)loggingIsEnabled;
- (void)setLoggingEnabled:(BOOL)flag;
- (BOOL)screenSecurityIsEnabled;
- (void)setScreenSecurity:(BOOL)flag;
- (NotificationType)notificationPreviewType;
- (void)setNotificationPreviewType:(NotificationType)type;
- (NSString *)nameForNotificationPreviewType:(NotificationType)notificationType;
- (BOOL)soundInForeground;
- (void)setSoundInForeground:(BOOL)enabled;
- (BOOL)hasRegisteredVOIPPush;
- (void)setHasRegisteredVOIPPush:(BOOL)enabled;
- (TSImageQuality)imageUploadQuality;
- (nullable NSString *)lastRanVersion;
- (NSString *)setAndGetCurrentVersion;
#pragma mark - Push Tokens
- (void)setPushToken:(NSString *)value;
- (nullable NSString *)getPushToken;
- (void)setVoipToken:(NSString *)value;
- (nullable NSString *)getVoipToken;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,12 +1,28 @@
#import "Constraints.h"
#import "PropertyListPreferences.h"
#import "Constraints.h"
#import "TSStorageHeaders.h"
#define SignalDatabaseCollection @"SignalPreferences"
NS_ASSUME_NONNULL_BEGIN
double const PropertyListPreferencesDefaultCallStreamDESBufferLevel = 0.5;
NSString *const PropertyListPreferencesSignalDatabaseCollection = @"SignalPreferences";
NSString *const PropertyListPreferencesKeyCallStreamDESBufferLevel = @"CallStreamDesiredBufferLevel";
NSString *const PropertyListPreferencesKeyScreenSecurity = @"Screen Security Key";
NSString *const PropertyListPreferencesKeyEnableDebugLog = @"Debugging Log Enabled Key";
NSString *const PropertyListPreferencesKeyNotificationPreviewType = @"Notification Preview Type Key";
NSString *const PropertyListPreferencesKeyHasSentAMessage = @"User has sent a message";
NSString *const PropertyListPreferencesKeyHasArchivedAMessage = @"User archived a message";
NSString *const PropertyListPreferencesKeyLastRunSignalVersion = @"SignalUpdateVersionKey";
NSString *const PropertyListPreferencesKeyPlaySoundInForeground = @"NotificationSoundInForeground";
NSString *const PropertyListPreferencesKeyHasRegisteredVoipPush = @"VOIPPushEnabled";
NSString *const PropertyListPreferencesKeyLastRecordedPushToken = @"LastRecordedPushToken";
NSString *const PropertyListPreferencesKeyLastRecordedVoipToken = @"LastRecordedVoipToken";
@implementation PropertyListPreferences
#pragma mark - Helpers
- (void)clear {
@synchronized(self) {
NSString *appDomain = NSBundle.mainBundle.bundleIdentifier;
@ -14,16 +30,200 @@
}
}
- (id)tryGetValueForKey:(NSString *)key {
- (nullable id)tryGetValueForKey:(NSString *)key
{
ows_require(key != nil);
return [TSStorageManager.sharedManager objectForKey:key inCollection:SignalDatabaseCollection];
return
[TSStorageManager.sharedManager objectForKey:key inCollection:PropertyListPreferencesSignalDatabaseCollection];
}
- (void)setValueForKey:(NSString *)key toValue:(id)value {
- (void)setValueForKey:(NSString *)key toValue:(nullable id)value
{
ows_require(key != nil);
[TSStorageManager.sharedManager setObject:value forKey:key inCollection:SignalDatabaseCollection];
[TSStorageManager.sharedManager setObject:value
forKey:key
inCollection:PropertyListPreferencesSignalDatabaseCollection];
}
#pragma mark - Specific Preferences
- (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth
{
id v = [self tryGetValueForKey:PropertyListPreferencesKeyCallStreamDESBufferLevel];
if (v == nil)
return PropertyListPreferencesDefaultCallStreamDESBufferLevel;
return [v doubleValue];
}
- (void)setCachedDesiredBufferDepth:(double)value
{
ows_require(value >= 0);
[self setValueForKey:PropertyListPreferencesKeyCallStreamDESBufferLevel toValue:@(value)];
}
- (BOOL)loggingIsEnabled
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyEnableDebugLog];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (BOOL)screenSecurityIsEnabled
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyScreenSecurity];
return preference ? [preference boolValue] : YES;
}
- (BOOL)getHasSentAMessage
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyHasSentAMessage];
if (preference) {
return [preference boolValue];
} else {
return NO;
}
}
- (BOOL)getHasArchivedAMessage
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyHasArchivedAMessage];
if (preference) {
return [preference boolValue];
} else {
return NO;
}
}
- (BOOL)hasRegisteredVOIPPush
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyHasRegisteredVoipPush];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (TSImageQuality)imageUploadQuality
{
// always return average image quality
return TSImageQualityMedium;
}
- (void)setScreenSecurity:(BOOL)flag
{
[self setValueForKey:PropertyListPreferencesKeyScreenSecurity toValue:@(flag)];
}
- (void)setHasRegisteredVOIPPush:(BOOL)enabled
{
[self setValueForKey:PropertyListPreferencesKeyHasRegisteredVoipPush toValue:@(enabled)];
}
- (void)setLoggingEnabled:(BOOL)flag
{
[self setValueForKey:PropertyListPreferencesKeyEnableDebugLog toValue:@(flag)];
}
- (nullable NSString *)lastRanVersion
{
return [NSUserDefaults.standardUserDefaults objectForKey:PropertyListPreferencesKeyLastRunSignalVersion];
}
- (void)setHasSentAMessage:(BOOL)enabled
{
[self setValueForKey:PropertyListPreferencesKeyHasSentAMessage toValue:@(enabled)];
}
- (void)setHasArchivedAMessage:(BOOL)enabled
{
[self setValueForKey:PropertyListPreferencesKeyHasArchivedAMessage toValue:@(enabled)];
}
- (NSString *)setAndGetCurrentVersion
{
NSString *currentVersion =
[NSString stringWithFormat:@"%@", NSBundle.mainBundle.infoDictionary[@"CFBundleVersion"]];
[NSUserDefaults.standardUserDefaults setObject:currentVersion
forKey:PropertyListPreferencesKeyLastRunSignalVersion];
[NSUserDefaults.standardUserDefaults synchronize];
return currentVersion;
}
#pragma mark Notification Preferences
- (BOOL)soundInForeground
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyPlaySoundInForeground];
if (preference) {
return [preference boolValue];
} else {
return YES;
}
}
- (void)setSoundInForeground:(BOOL)enabled
{
[self setValueForKey:PropertyListPreferencesKeyPlaySoundInForeground toValue:@(enabled)];
}
- (void)setNotificationPreviewType:(NotificationType)type
{
[self setValueForKey:PropertyListPreferencesKeyNotificationPreviewType toValue:@(type)];
}
- (NotificationType)notificationPreviewType
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyNotificationPreviewType];
if (preference) {
return [preference unsignedIntegerValue];
} else {
return NotificationNamePreview;
}
}
- (NSString *)nameForNotificationPreviewType:(NotificationType)notificationType
{
switch (notificationType) {
case NotificationNamePreview:
return NSLocalizedString(@"NOTIFICATIONS_SENDER_AND_MESSAGE", nil);
case NotificationNameNoPreview:
return NSLocalizedString(@"NOTIFICATIONS_SENDER_ONLY", nil);
case NotificationNoNameNoPreview:
return NSLocalizedString(@"NOTIFICATIONS_NONE", nil);
default:
DDLogWarn(@"Undefined NotificationType in Settings");
return @"";
}
}
#pragma mark - Push Tokens
- (void)setPushToken:(NSString *)value
{
[self setValueForKey:PropertyListPreferencesKeyLastRecordedPushToken toValue:value];
}
- (nullable NSString *)getPushToken
{
return [self tryGetValueForKey:PropertyListPreferencesKeyLastRecordedPushToken];
}
- (void)setVoipToken:(NSString *)value
{
[self setValueForKey:PropertyListPreferencesKeyLastRecordedVoipToken toValue:value];
}
- (nullable NSString *)getVoipToken
{
return [self tryGetValueForKey:PropertyListPreferencesKeyLastRecordedVoipToken];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -11,7 +11,7 @@
#import "Environment.h"
#import "LockInteractionController.h"
#import "OWSDatabaseMigrationRunner.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "RecentCallManager.h"
#import "SignalKeyingStorage.h"
@ -102,16 +102,17 @@
#pragma mark Upgrading to 2.1 - Needs to register VOIP token + Removing video cache folder
+ (void)nonBlockingPushRegistration {
__block failedBlock failedBlock = ^(NSError *error) {
DDLogError(@"Failed to register VOIP push token: %@", error.debugDescription);
void (^failedBlock)(NSError *) = ^(NSError *error) {
DDLogError(@"Failed to register VOIP push token: %@", error.debugDescription);
};
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
[TSAccountManager registerForPushNotifications:pushToken
voipToken:voipToken
success:^{
DDLogWarn(@"Registered for VOIP Push.");
}
failure:failedBlock];
[[TSAccountManager sharedInstance]
registerForPushNotificationsWithPushToken:pushToken
voipToken:voipToken
success:^{
DDLogWarn(@"Registered for VOIP Push.");
}
failure:failedBlock];
}
failure:failedBlock];
}

View File

@ -8,6 +8,11 @@
#import <CollapsingFutures.h>
#import <PushKit/PushKit.h>
#import <UIKit/UIApplication.h>
NS_ASSUME_NONNULL_BEGIN
@class UILocalNotification;
#define Signal_Thread_UserInfo_Key @"Signal_Thread_Id"
#define Signal_Message_UserInfo_Key @"Signal_Message_Id"
@ -43,23 +48,20 @@ typedef void (^pushTokensSuccessBlock)(NSString *pushToken, NSString *voipToken)
* @param success Completion block that is passed the token as a parameter
* @param failure Failure block, executed when failed to get push token
*/
- (void)requestPushTokenWithSuccess:(pushTokensSuccessBlock)success failure:(void (^)(NSError *))failure;
/**
* Registers for Users Notifications. By doing this on launch, we are sure that the correct categories of user
* notifications is registered.
*/
- (void)validateUserNotificationSettings;
/**
* The pushNotification and userNotificationFutureSource are accessed by the App Delegate after requested permissions.
*/
@property TOCFutureSource *pushNotificationFutureSource;
@property TOCFutureSource *userNotificationFutureSource;
@property TOCFutureSource *pushKitNotificationFutureSource;
@property (nullable, atomic, readwrite, strong) TOCFutureSource *pushNotificationFutureSource;
@property (nullable, atomic, readwrite, strong) TOCFutureSource *userNotificationFutureSource;
@property (nullable, atomic, readwrite, strong) TOCFutureSource *pushKitNotificationFutureSource;
- (TOCFuture *)registerPushKitNotificationFuture;
- (BOOL)supportsVOIPPush;
@ -85,3 +87,5 @@ typedef void (^pushTokensSuccessBlock)(NSString *pushToken, NSString *voipToken)
completionHandler:(void (^)())completionHandler;
@end
NS_ASSUME_NONNULL_END

View File

@ -13,7 +13,7 @@
#import "NSDate+millisecondTimeStamp.h"
#import "NotificationTracker.h"
#import "OWSContactsManager.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "RPServerRequestsManager.h"
#import "TSOutgoingMessage.h"
#import "TSSocketManager.h"
@ -346,20 +346,6 @@
}];
}
- (TOCFuture *)registerForUserNotificationsFuture {
self.userNotificationFutureSource = [TOCFutureSource new];
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
categories:[NSSet setWithObjects:[self userNotificationsCallCategory],
[self fullNewMessageNotificationCategory],
[self userNotificationsCallBackCategory],
nil]];
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
return self.userNotificationFutureSource.future;
}
- (UIUserNotificationCategory *)fullNewMessageNotificationCategory {
UIMutableUserNotificationAction *action_markRead = [UIMutableUserNotificationAction new];
action_markRead.identifier = Signal_Message_MarkAsRead_Identifier;
@ -443,10 +429,16 @@
return UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge;
}
- (void)validateUserNotificationSettings {
[[self registerForUserNotificationsFuture] thenDo:^(id value){
// Nothing to do, just making sure we are registered for User Notifications.
}];
- (void)validateUserNotificationSettings
{
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
categories:[NSSet setWithObjects:[self userNotificationsCallCategory],
[self fullNewMessageNotificationCategory],
[self userNotificationsCallBackCategory],
nil]];
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
}
- (BOOL)applicationIsActive {

View File

@ -7,7 +7,9 @@
//
#import <AFNetworking/AFNetworking.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class PhoneNumber;
@interface RPAPICall : NSObject
@ -18,14 +20,15 @@ typedef NS_ENUM(NSInteger, HTTPMethod) { HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DEL
@property (nonatomic, readonly) NSString *endPoint;
@property (nonatomic, readonly) HTTPMethod method;
@property (nonatomic, readonly) NSDictionary *parameters;
@property (nonatomic, readonly) NSMutableDictionary *parameters;
@property (nonatomic, readonly) AFHTTPRequestSerializer<AFURLRequestSerialization> *requestSerializer;
@property (nonatomic, readonly) AFHTTPResponseSerializer<AFURLResponseSerialization> *responseSerializer;
#pragma mark API Call Contstructors
+ (RPAPICall *)registerPushNotificationWithPushToken:(NSData *)pushToken voipToken:(NSData *)voipToken;
+ (RPAPICall *)unregisterWithPushToken:(NSData *)pushToken;
+ (RPAPICall *)verifyWithTSToken:(NSString *)tsToken attributesParameters:(NSDictionary *)attributes;
+ (RPAPICall *)verifyWithTSToken:(NSString *)tsToken signalingKey:(NSData *)signalingKey;
+ (RPAPICall *)registerPushNotificationWithPushToken:(NSString *)pushToken voipToken:(NSString *)voipToken;
@end
NS_ASSUME_NONNULL_END

View File

@ -9,51 +9,59 @@
#import <SignalServiceKit/TSAccountManager.h>
#import "Constraints.h"
#import "CryptoTools.h"
#import "NSData+ows_StripToken.h"
#import "PhoneNumber.h"
#import "RPAPICall.h"
#import "SignalKeyingStorage.h"
#import "Util.h"
NS_ASSUME_NONNULL_BEGIN
#define CLAIMED_INTEROP_VERSION_IN_INITIATE_SIGNAL 1
NSString *const RPAPICallPushTokenKey = @"apnRegistrationId";
NSString *const RPAPICallVoipTokenKey = @"voipRegistrationId";
NSString *const RPAPICallSignalingKeyKey = @"signalingKey";
@interface RPAPICall ()
@property (nonatomic, readwrite) NSString *endPoint;
@property (nonatomic, readwrite) HTTPMethod method;
@property (nonatomic, readwrite) NSDictionary *parameters;
@property (nonatomic, readwrite) NSMutableDictionary *parameters;
@property (nonatomic, readwrite) AFHTTPRequestSerializer<AFURLRequestSerialization> *requestSerializer;
@property (nonatomic, readwrite) AFHTTPResponseSerializer<AFURLResponseSerialization> *responseSerializer;
@end
@implementation RPAPICall
+ (RPAPICall *)defaultAPICall {
RPAPICall *apiCall = [[RPAPICall alloc] init];
apiCall.parameters = @{};
apiCall.parameters = [NSMutableDictionary new];
apiCall.requestSerializer = [self basicAuthenticationSerializer];
apiCall.responseSerializer = [AFHTTPResponseSerializer serializer];
return apiCall;
}
+ (RPAPICall *)verifyWithTSToken:(NSString *)tsToken attributesParameters:(NSDictionary *)attributes {
+ (RPAPICall *)verifyWithTSToken:(NSString *)tsToken signalingKey:(NSData *)signalingKey
{
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_PUT;
apiCall.endPoint = [NSString stringWithFormat:@"/api/v1/accounts/token/%@", tsToken];
apiCall.parameters = attributes;
apiCall.parameters[RPAPICallSignalingKeyKey] = [signalingKey encodedAsBase64];
return apiCall;
}
+ (RPAPICall *)registerPushNotificationWithPushToken:(NSData *)pushToken voipToken:(NSData *)voipToken {
+ (RPAPICall *)registerPushNotificationWithPushToken:(NSString *)pushToken voipToken:(NSString *)voipToken
{
RPAPICall *apiCall = [self defaultAPICall];
if (voipToken) {
apiCall.parameters = @{ @"voip" : [voipToken ows_tripToken] };
} else {
DDLogWarn(@"No VoIP push token registered, might experience some issues while in background.");
}
apiCall.method = HTTP_PUT;
apiCall.endPoint = [NSString stringWithFormat:@"/apn/%@", [pushToken ows_tripToken]];
apiCall.parameters[RPAPICallPushTokenKey] = pushToken;
apiCall.parameters[RPAPICallVoipTokenKey] = voipToken;
apiCall.endPoint = @"/api/v1/accounts/apn";
return apiCall;
}
@ -61,7 +69,6 @@
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_DELETE;
apiCall.endPoint = [NSString stringWithFormat:@"/apn/%@", pushToken.encodedAsHexString];
apiCall.parameters = nil;
apiCall.requestSerializer = [self basicAuthenticationSerializer];
return apiCall;
}
@ -194,4 +201,11 @@
}
*/
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ %@", [super description], self.endPoint];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -9,8 +9,6 @@
#import <Foundation/Foundation.h>
#import "RPAPICall.h"
#import <CollapsingFutures.h>
@interface RPServerRequestsManager : NSObject
+ (instancetype)sharedManager;
@ -19,6 +17,4 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
- (TOCFuture *)futureForRequest:(RPAPICall *)apiCall;
@end

View File

@ -17,7 +17,6 @@
@end
@implementation RPServerRequestsManager
+ (instancetype)sharedManager {
@ -45,7 +44,10 @@
- (void)performRequest:(RPAPICall *)apiCall
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
DDLogInfo(@"%@ Making request: %@", self.tag, apiCall);
self.operationManager.requestSerializer = apiCall.requestSerializer;
self.operationManager.responseSerializer = apiCall.responseSerializer;
@ -87,18 +89,16 @@
}
}
- (TOCFuture *)futureForRequest:(RPAPICall *)apiCall {
TOCFutureSource *requestFutureSource = [TOCFutureSource new];
#pragma mark - Logging
[self performRequest:apiCall
success:^(NSURLSessionDataTask *task, id responseObject) {
[requestFutureSource trySetResult:task.response];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
[requestFutureSource trySetFailure:error];
}];
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
return [requestFutureSource future];
- (NSString *)tag
{
return self.class.tag;
}
@end

View File

@ -6,14 +6,27 @@
// Copyright © 2015 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RPAccountManager : NSObject
+ (void)registrationWithTsToken:(NSString *)tsToken
pushToken:(NSString *)pushToken
voipToken:(NSString *)voipPushToken
success:(void (^)())success
failure:(void (^)(NSError *))failure;
+ (instancetype)sharedInstance;
- (void)registerWithTsToken:(NSString *)tsToken
success:(void (^)())success
failure:(void (^)(NSError *))failure;
/**
* Register's the device's push notification token with the server
*
* @param pushToken Apple's Push Token
*/
- (void)registerForPushNotificationsWithPushToken:(NSString *)pushToken
voipToken:(NSString *)voipToken
success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler
NS_SWIFT_NAME(registerForPushNotifications(pushToken:voipToken:success:failure:));
@end
NS_ASSUME_NONNULL_END

View File

@ -15,90 +15,97 @@
#import "RPServerRequestsManager.h"
#import "SignalKeyingStorage.h"
@interface RedPhoneAccountAttributes : MTLModel
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy, readonly) NSString *signalingKey;
@property (nonatomic, copy, readonly) NSString *apnRegistrationId;
@property (nonatomic, copy, readonly) NSString *voipRegistrationId;
@interface RPAccountManager ()
- (instancetype)initWithSignalingCipherKey:(NSData *)signalingCipherKey
signalingMacKey:(NSData *)signalingMacKey
signalingExtraKey:(NSData *)signalingExtraKey
apnRegistrationId:(NSString *)apnRegistrationId
voipRegistrationId:(NSString *)voipRegistrationId;
@end
@implementation RedPhoneAccountAttributes
- (instancetype)initWithSignalingCipherKey:(NSData *)signalingCipherKey
signalingMacKey:(NSData *)signalingMacKey
signalingExtraKey:(NSData *)signalingExtraKey
apnRegistrationId:(NSString *)apnRegistrationId
voipRegistrationId:(NSString *)voipRegistrationId {
self = [super init];
if (self) {
_signalingKey = @[ signalingCipherKey, signalingMacKey, signalingExtraKey ].ows_concatDatas.encodedAsBase64;
_apnRegistrationId = apnRegistrationId;
_voipRegistrationId = voipRegistrationId;
}
return self;
}
- (NSDictionary *)dictionaryValue {
NSMutableDictionary *dictionaryValue = [[super dictionaryValue] mutableCopy];
if (!_voipRegistrationId) {
[dictionaryValue removeObjectForKey:@"voipRegistrationId"];
}
return dictionaryValue;
}
@property (nonatomic, readonly, strong) RPServerRequestsManager *requestManager;
@end
@implementation RPAccountManager
+ (void)generateKeyingMaterial {
- (instancetype)initWithRequestManager:(RPServerRequestsManager *)requestManager
{
self = [super init];
if (!self) {
return self;
}
_requestManager = requestManager;
return self;
}
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
static RPAccountManager *sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initWithRequestManager:[RPServerRequestsManager sharedManager]];
});
return sharedInstance;
}
- (NSData *)generateSignalingKey
{
[SignalKeyingStorage generateServerAuthPassword];
[SignalKeyingStorage generateSignaling];
}
+ (NSDictionary *)attributesWithPushToken:(NSString *)pushToken voipToken:(NSString *)voipPushToken {
NSData *signalingCipherKey = SignalKeyingStorage.signalingCipherKey;
NSData *signalingMacKey = SignalKeyingStorage.signalingMacKey;
NSData *signalingExtraKeyData = SignalKeyingStorage.signalingExtraKey;
NSData *signalingExtraKey = SignalKeyingStorage.signalingExtraKey;
return [[RedPhoneAccountAttributes alloc] initWithSignalingCipherKey:signalingCipherKey
signalingMacKey:signalingMacKey
signalingExtraKey:signalingExtraKeyData
apnRegistrationId:pushToken
voipRegistrationId:voipPushToken]
.dictionaryValue;
return @[ signalingCipherKey, signalingMacKey, signalingExtraKey ].ows_concatDatas;
}
+ (void)registrationWithTsToken:(NSString *)tsToken
pushToken:(NSString *)pushToken
voipToken:(NSString *)voipPushToken
success:(void (^)())success
failure:(void (^)(NSError *))failure {
[self generateKeyingMaterial];
[[RPServerRequestsManager sharedManager]
performRequest:[RPAPICall verifyWithTSToken:tsToken
attributesParameters:[self attributesWithPushToken:pushToken voipToken:voipPushToken]]
- (void)registerWithTsToken:(NSString *)tsToken
success:(void (^)())success
failure:(void (^)(NSError *))failure
{
RPAPICall *request = [RPAPICall verifyWithTSToken:tsToken signalingKey:[self generateSignalingKey]];
[self.requestManager performRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
success();
DDLogInfo(@"%@ Successfully verified RedPhone account.", self.tag);
success();
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
failure(error);
DDLogError(@"%@ Failed to verify RedPhone account with error: %@", self.tag, error);
failure(error);
}];
}
+ (void)unregister {
- (void)registerForPushNotificationsWithPushToken:(NSString *)pushToken
voipToken:(NSString *)voipToken
success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler
{
RPAPICall *request = [RPAPICall registerPushNotificationWithPushToken:pushToken voipToken:voipToken];
[self.requestManager performRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
DDLogInfo(@"%@ Successfully updated push tokens.", self.tag);
successHandler();
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
DDLogError(@"%@ Failed to update push tokens: %@", self.tag, error);
failureHandler(error);
}];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,20 @@
// Created by Michael Kirk on 10/25/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
NS_ASSUME_NONNULL_BEGIN
/**
* A minimal DDLog wrapper for swift.
*/
NS_SWIFT_NAME(Logger)
@interface OWSLogger : NSObject
+ (void)verbose:(NSString *)logString;
+ (void)debug:(NSString *)logString;
+ (void)info:(NSString *)logString;
+ (void)warn:(NSString *)logString;
+ (void)error:(NSString *)logString;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,37 @@
// Created by Michael Kirk on 10/25/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSLogger.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSLogger
+ (void)verbose:(NSString *)logString
{
DDLogVerbose(logString);
}
+ (void)debug:(NSString *)logString
{
DDLogDebug(logString);
}
+ (void)info:(NSString *)logString
{
DDLogInfo(logString);
}
+ (void)warn:(NSString *)logString
{
DDLogWarn(logString);
}
+ (void)error:(NSString *)logString
{
DDLogError(logString);
}
@end
NS_ASSUME_NONNULL_END

View File

@ -7,23 +7,28 @@
//
#import "AdvancedSettingsTableViewController.h"
#import <PastelogKit/Pastelog.h>
#import "DebugLogger.h"
#import "Environment.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "RPAccountManager.h"
#import "Signal-Swift.h"
#import "TSAccountManager.h"
#import <PastelogKit/Pastelog.h>
#import <PromiseKit/AnyPromise.h>
NS_ASSUME_NONNULL_BEGIN
@interface AdvancedSettingsTableViewController ()
@property NSArray *sectionsArray;
@property (strong, nonatomic) UITableViewCell *enableLogCell;
@property (strong, nonatomic) UITableViewCell *submitLogCell;
@property (strong, nonatomic) UITableViewCell *registerPushCell;
@property (strong, nonatomic) UISwitch *enableLogSwitch;
@end
@implementation AdvancedSettingsTableViewController
@ -35,8 +40,10 @@
}
- (instancetype)init {
self.sectionsArray =
@[ NSLocalizedString(@"LOGGING_SECTION", nil), NSLocalizedString(@"PUSH_REGISTER_TITLE", nil) ];
self.sectionsArray = @[
NSLocalizedString(@"LOGGING_SECTION", nil),
NSLocalizedString(@"PUSH_REGISTER_TITLE", @"Used in table section header and alert view title contexts")
];
return [super initWithStyle:UITableViewStyleGrouped];
}
@ -84,7 +91,8 @@
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.sectionsArray objectAtIndex:(NSUInteger)section];
}
@ -111,20 +119,23 @@
if ([tableView cellForRowAtIndexPath:indexPath] == self.submitLogCell) {
[Pastelog submitLogs];
} else if ([tableView cellForRowAtIndexPath:indexPath] == self.registerPushCell) {
__block failedPushRegistrationBlock failure = ^(NSError *error) {
SignalAlertView(NSLocalizedString(@"PUSH_REGISTER_TITLE", nil), NSLocalizedString(@"REGISTRATION_BODY", nil));
};
OWSAccountManager *accountManager =
[[OWSAccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]
redPhoneAccountManager:[RPAccountManager sharedInstance]];
OWSSyncPushTokensJob *syncJob = [[OWSSyncPushTokensJob alloc] initWithPushManager:[PushManager sharedManager]
accountManager:accountManager
preferences:[Environment preferences]];
syncJob.uploadOnlyIfStale = NO;
[syncJob run]
.then(^{
SignalAlertView(NSLocalizedString(@"PUSH_REGISTER_SUCCESS", @"Alert title"), nil);
})
.catch(^(NSError *error) {
SignalAlertView(NSLocalizedString(@"REGISTRATION_BODY", @"Alert title"), error.localizedDescription);
});
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
[TSAccountManager registerForPushNotifications:pushToken
voipToken:voipToken
success:^{
SignalAlertView(NSLocalizedString(@"PUSH_REGISTER_TITLE", nil),
NSLocalizedString(@"PUSH_REGISTER_SUCCESS", nil));
}
failure:failure];
}
failure:failure];
} else {
DDLogDebug(@"%@ Ignoring cell selection at indexPath: %@", self.tag, indexPath);
}
}
@ -142,4 +153,18 @@
[self.tableView reloadData];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -7,22 +7,54 @@
//
#import "CodeVerificationViewController.h"
#import <SignalServiceKit/TSStorageManager+keyingMaterial.h>
#import "OWSContactsManager.h"
#import "Environment.h"
#import "LocalizableText.h"
#import "PushManager.h"
#import "AppDelegate.h"
#import "RPAccountManager.h"
#import "RPServerRequestsManager.h"
#import "TSAccountManager.h"
#import "Signal-Swift.h"
#import "SignalsNavigationController.h"
#import "SignalsViewController.h"
#import <PromiseKit/AnyPromise.h>
#import <SignalServiceKit/OWSError.h>
#import <SignalServiceKit/TSAccountManager.h>
#import <SignalServiceKit/TSStorageManager+keyingMaterial.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const kCompletedRegistrationSegue = @"CompletedRegistration";
@interface CodeVerificationViewController ()
@property (nonatomic, strong, readonly) OWSAccountManager *accountManager;
@end
@implementation CodeVerificationViewController
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
_accountManager = [[OWSAccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]
redPhoneAccountManager:[RPAccountManager sharedInstance]];
return self;
}
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_accountManager = [[OWSAccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]
redPhoneAccountManager:[RPAccountManager sharedInstance]];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeKeyboardHandlers];
@ -50,156 +82,80 @@
[self adjustScreenSizes];
}
- (IBAction)verifyChallengeAction:(id)sender {
- (void)startActivityIndicator
{
[self.submitCodeSpinner startAnimating];
[self enableServerActions:NO];
[_challengeTextField resignFirstResponder];
[self registerWithSuccess:^{
[_submitCodeSpinner stopAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[TSAccountManager didRegister];
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController
dismissViewControllerAnimated:YES
completion:^{
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined ||
ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusRestricted) {
UIAlertController *controller = [UIAlertController
alertControllerWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_WELCOME", nil)
message:NSLocalizedString(@"REGISTER_CONTACTS_BODY", nil)
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(
@"REGISTER_CONTACTS_CONTINUE", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self setupContacts];
}]];
[[UIApplication sharedApplication]
.keyWindow.rootViewController presentViewController:controller
animated:YES
completion:nil];
} else {
[self setupContacts];
}
}];
});
});
}
failure:^(NSError *error) {
[self enableServerActions:YES];
[_submitCodeSpinner stopAnimating];
DDLogError(@"Error: %@", error.localizedDescription);
}];
[self.challengeTextField resignFirstResponder];
}
- (void)setupContacts {
[[Environment getCurrent].contactsManager doAfterEnvironmentInitSetup];
- (void)stopActivityIndicator
{
[self enableServerActions:YES];
[self.submitCodeSpinner stopAnimating];
}
- (IBAction)verifyChallengeAction:(id)sender
{
[self startActivityIndicator];
[self.accountManager registerWithVerificationCode:[self validationCodeFromTextField]]
.then(^{
DDLogInfo(@"%@ Successfully registered Signal account.", self.tag);
dispatch_async(dispatch_get_main_queue(), ^{
[self stopActivityIndicator];
[self performSegueWithIdentifier:kCompletedRegistrationSegue sender:nil];
});
})
.catch(^(NSError *_Nonnull error) {
DDLogError(@"%@ error verifying challenge: %@", self.tag, error);
dispatch_async(dispatch_get_main_queue(), ^{
[self stopActivityIndicator];
[self presentAlertWithVerificationError:error];
});
});
}
- (void)presentAlertWithVerificationError:(NSError *)error
{
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:NSLocalizedString(@"REGISTRATION_VERIFICATION_FAILED_TITLE", @"Alert view title")
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"DISMISS_BUTTON_TEXT", nil)
style:UIAlertActionStyleDefault
handler:nil];
[alertController addAction:dismissAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (NSString *)validationCodeFromTextField {
return [_challengeTextField.text stringByReplacingOccurrencesOfString:@"-" withString:@""];
return [self.challengeTextField.text stringByReplacingOccurrencesOfString:@"-" withString:@""];
}
- (TOCFuture *)pushRegistration {
TOCFutureSource *pushAndRegisterFuture = [[TOCFutureSource alloc] init];
[[PushManager sharedManager] validateUserNotificationSettings];
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
NSMutableArray *pushTokens = [NSMutableArray arrayWithObject:pushToken];
if (voipToken) {
[pushTokens addObject:voipToken];
}
[pushAndRegisterFuture trySetResult:pushTokens];
}
failure:^(NSError *error) {
[pushAndRegisterFuture trySetFailure:error];
}];
return pushAndRegisterFuture.future;
}
- (TOCFuture *)textSecureRegistrationFuture:(NSArray *)pushTokens {
TOCFutureSource *textsecureRegistration = [[TOCFutureSource alloc] init];
[TSAccountManager verifyAccountWithCode:[self validationCodeFromTextField]
pushToken:pushTokens[0]
voipToken:([pushTokens count] == 2) ? pushTokens.lastObject : nil
success:^{
[textsecureRegistration trySetResult:@YES];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender
{
DDLogInfo(@"%@ preparing for CompletedRegistrationSeque", self.tag);
if ([segue.identifier isEqualToString:kCompletedRegistrationSegue]) {
if (![segue.destinationViewController isKindOfClass:[SignalsNavigationController class]]) {
DDLogError(@"%@ Unexpected destination view controller: %@", self.tag, segue.destinationViewController);
return;
}
failure:^(NSError *error) {
[textsecureRegistration trySetFailure:error];
}];
return textsecureRegistration.future;
}
SignalsNavigationController *snc = (SignalsNavigationController *)segue.destinationViewController;
- (void)registerWithSuccess:(void (^)())success failure:(void (^)(NSError *))failure {
[_submitCodeSpinner startAnimating];
__block NSArray<NSString *> *pushTokens;
TOCFuture *tsRegistrationFuture = [[self pushRegistration] then:^id(NSArray<NSString *> *tokens) {
pushTokens = tokens;
return [self textSecureRegistrationFuture:pushTokens];
}];
TOCFuture *redphoneRegistrationFuture = [tsRegistrationFuture then:^id(id value) {
return [[self getRPRegistrationToken] then:^(NSString *registrationFuture) {
return [self redphoneRegistrationWithTSToken:registrationFuture
pushToken:pushTokens[0]
voipToken:([pushTokens count] == 2) ? pushTokens.lastObject : nil];
}];
}];
[redphoneRegistrationFuture thenDo:^(id value) {
success();
}];
[redphoneRegistrationFuture catchDo:^(NSError *error) {
failure(error);
}];
}
- (TOCFuture *)getRPRegistrationToken {
TOCFutureSource *redPhoneTokenFuture = [[TOCFutureSource alloc] init];
[TSAccountManager obtainRPRegistrationToken:^(NSString *rpRegistrationToken) {
[redPhoneTokenFuture trySetResult:rpRegistrationToken];
}
failure:^(NSError *error) {
[redPhoneTokenFuture trySetFailure:error];
}];
return redPhoneTokenFuture.future;
}
- (TOCFuture *)redphoneRegistrationWithTSToken:(NSString *)tsToken
pushToken:(NSString *)pushToken
voipToken:(NSString *)voipToken {
TOCFutureSource *rpRegistration = [[TOCFutureSource alloc] init];
[RPAccountManager registrationWithTsToken:tsToken
pushToken:pushToken
voipToken:voipToken
success:^{
[rpRegistration trySetResult:@YES];
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.window.rootViewController = snc;
if (![snc.topViewController isKindOfClass:[SignalsViewController class]]) {
DDLogError(@"%@ Unexpected top view controller: %@", self.tag, snc.topViewController);
return;
}
failure:^(NSError *error) {
[rpRegistration trySetFailure:error];
}];
return rpRegistration.future;
DDLogDebug(@"%@ notifying signals view controller of new user.", self.tag);
SignalsViewController *signalsViewController = (SignalsViewController *)snc.topViewController;
signalsViewController.newlyRegisteredUser = YES;
}
}
#pragma mark - Send codes again
@ -208,13 +164,15 @@
[_requestCodeAgainSpinner startAnimating];
[TSAccountManager rerequestSMSWithSuccess:^{
[self enableServerActions:YES];
[_requestCodeAgainSpinner stopAnimating];
DDLogInfo(@"%@ Successfully requested SMS code", self.tag);
[self enableServerActions:YES];
[_requestCodeAgainSpinner stopAnimating];
}
failure:^(NSError *error) {
[self showRegistrationErrorMessage:error];
[self enableServerActions:YES];
[_requestCodeAgainSpinner stopAnimating];
DDLogError(@"%@ Failed to request SMS code with error: %@", self.tag, error);
[self showRegistrationErrorMessage:error];
[self enableServerActions:YES];
[_requestCodeAgainSpinner stopAnimating];
}];
}
@ -223,13 +181,16 @@
[_requestCallSpinner startAnimating];
[TSAccountManager rerequestVoiceWithSuccess:^{
[self enableServerActions:YES];
[_requestCallSpinner stopAnimating];
DDLogInfo(@"%@ Successfully requested voice code", self.tag);
[self enableServerActions:YES];
[_requestCallSpinner stopAnimating];
}
failure:^(NSError *error) {
[self showRegistrationErrorMessage:error];
[self enableServerActions:YES];
[_requestCallSpinner stopAnimating];
DDLogError(@"%@ Failed to request voice code with error: %@", self.tag, error);
[self showRegistrationErrorMessage:error];
[self enableServerActions:YES];
[_requestCallSpinner stopAnimating];
}];
}
@ -303,4 +264,18 @@
_headerConstraint.constant = blueHeaderHeight;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) IBOutlet UIView *qrContainer;
@property (strong, nonatomic) IBOutlet UIView *privacyVerificationQRCodeFrame;
@property (strong, nonatomic) IBOutlet UIImageView *privacyVerificationQRCode;
@property (strong, nonatomic) IBOutlet CopyableLabel *privacyVerificationFingerprint;
@property (strong, nonatomic) IBOutlet OWSCopyableLabel *privacyVerificationFingerprint;
@property (strong, nonatomic) IBOutlet UILabel *instructionsLabel;
@property (strong, nonatomic) IBOutlet UIButton *scanButton;

View File

@ -4,7 +4,7 @@
#import "InboxTableViewCell.h"
#import "Environment.h"
#import "OWSAvatarBuilder.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "TSMessagesManager.h"

View File

@ -26,7 +26,7 @@
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSOutgoingMessageCollectionViewCell.h"
#import "PhoneManager.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "SignalKeyingStorage.h"
#import "TSAttachmentPointer.h"
#import "TSCall.h"

View File

@ -6,9 +6,9 @@
// Copyright (c) 2015 Open Whisper Systems. All rights reserved.
//
#import "Environment.h"
#import "NotificationSettingsOptionsViewController.h"
#import "PreferencesUtil.h"
#import "Environment.h"
#import "PropertyListPreferences.h"
@interface NotificationSettingsOptionsViewController ()
@property NSArray *options;

View File

@ -10,7 +10,7 @@
#import "Environment.h"
#import "NotificationSettingsOptionsViewController.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
@interface NotificationSettingsViewController ()

View File

@ -8,11 +8,11 @@
#import "PrivacySettingsTableViewController.h"
#import <25519/Curve25519.h>
#import "DJWActionSheet+OWS.h"
#import "Environment.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "UIUtil.h"
#import <25519/Curve25519.h>
@interface PrivacySettingsTableViewController ()

View File

@ -9,7 +9,7 @@
#import "SettingsTableViewController.h"
#import "Environment.h"
#import "PreferencesUtil.h"
#import "PropertyListPreferences.h"
#import "TSAccountManager.h"
#import "UIUtil.h"

View File

@ -18,7 +18,7 @@
@property (nonatomic, retain) IBOutlet UITableView *tableView;
@property (nonatomic, strong) IBOutlet UILabel *emptyBoxLabel;
@property (nonatomic) BOOL newlyRegisteredUser;
@property (nonatomic, retain) CallState *latestCall;
- (void)presentThread:(TSThread *)thread keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing;

View File

@ -6,19 +6,22 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "InboxTableViewCell.h"
#import "UIUtil.h"
#import "SignalsViewController.h"
#import "AppDelegate.h"
#import "InCallViewController.h"
#import "InboxTableViewCell.h"
#import "MessagesViewController.h"
#import "NSDate+millisecondTimeStamp.h"
#import "OWSContactsManager.h"
#import "PreferencesUtil.h"
#import "SignalsViewController.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "RPAccountManager.h"
#import "Signal-Swift.h"
#import "TSAccountManager.h"
#import "TSDatabaseView.h"
#import "TSGroupThread.h"
#import "TSStorageManager.h"
#import "UIUtil.h"
#import "VersionMigrations.h"
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSMessagesManager.h>
@ -29,8 +32,6 @@
#define CELL_HEIGHT 72.0f
#define HEADER_HEIGHT 44.0f
static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
@interface SignalsViewController ()
@property (nonatomic, strong) YapDatabaseConnection *editingDbConnection;
@ -183,11 +184,62 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (![TSAccountManager isRegistered]) {
[self performSegueWithIdentifier:kShowSignupFlowSegue sender:self];
if (self.newlyRegisteredUser) {
[self didAppearForNewlyRegisteredUser];
}
}
- (void)didAppearForNewlyRegisteredUser
{
[self promptNewUserForContactsWithCompletion:^{
[self ensureNotificationsUpToDate];
}];
}
- (void)promptNewUserForContactsWithCompletion:(void (^)())completionHandler
{
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
switch (status) {
case kABAuthorizationStatusNotDetermined:
case kABAuthorizationStatusRestricted: {
UIAlertController *controller =
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_WELCOME", nil)
message:NSLocalizedString(@"REGISTER_CONTACTS_BODY", nil)
preferredStyle:UIAlertControllerStyleAlert];
[controller
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_CONTINUE", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
[[Environment getCurrent].contactsManager doAfterEnvironmentInitSetup];
}]];
[self presentViewController:controller animated:YES completion:completionHandler];
break;
}
default: {
DDLogError(@"%@ Unexpected for new user to have kABAuthorizationStatus:%ld", self.tag, status);
[[Environment getCurrent].contactsManager doAfterEnvironmentInitSetup];
completionHandler();
break;
}
}
}
- (void)ensureNotificationsUpToDate
{
OWSAccountManager *accountManager =
[[OWSAccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]
redPhoneAccountManager:[RPAccountManager sharedInstance]];
OWSSyncPushTokensJob *syncPushTokensJob =
[[OWSSyncPushTokensJob alloc] initWithPushManager:[PushManager sharedManager]
accountManager:accountManager
preferences:[Environment preferences]];
[syncPushTokensJob run];
}
- (void)tableViewSetUp {
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
}
@ -363,16 +415,16 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
- (void)presentThread:(TSThread *)thread keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing {
dispatch_async(dispatch_get_main_queue(), ^{
MessagesViewController *mvc = [[UIStoryboard storyboardWithName:@"Storyboard" bundle:NULL]
instantiateViewControllerWithIdentifier:@"MessagesViewController"];
MessagesViewController *mvc = [[UIStoryboard storyboardWithName:AppDelegateStoryboardMain bundle:NULL]
instantiateViewControllerWithIdentifier:@"MessagesViewController"];
if (self.presentedViewController) {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
[self.navigationController popToRootViewControllerAnimated:YES];
if (self.presentedViewController) {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
[self.navigationController popToRootViewControllerAnimated:YES];
[mvc configureForThread:thread keyboardOnViewAppearing:keyboardOnViewAppearing];
[self.navigationController pushViewController:mvc animated:YES];
[mvc configureForThread:thread keyboardOnViewAppearing:keyboardOnViewAppearing];
[self.navigationController pushViewController:mvc animated:YES];
});
}
@ -565,4 +617,16 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
_emptyBoxLabel.attributedText = fullLabelString;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end

View File

@ -3,6 +3,7 @@
import UIKit
@objc(OWSCopyableLabel)
class CopyableLabel : UILabel {
deinit {

View File

@ -0,0 +1,202 @@
// Created by Michael Kirk on 10/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
import XCTest
import PromiseKit
struct VerificationFailedError : Error { }
struct FailedToGetRPRegistrationTokenError : Error { }
struct FailedToRegisterWithRedphoneError : Error { }
enum PushNotificationRequestResult : String {
case FailTSOnly = "FailTSOnly",
FailRPOnly = "FailRPOnly",
FailBoth = "FailBoth",
Succeed = "Succeed"
}
class FailingTSAccountManager : TSAccountManager {
let phoneNumberAwaitingVerification = "+13235555555"
override func verifyAccount(withCode: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) -> Void {
failure(VerificationFailedError())
}
override func registerForPushNotifications(pushToken: String, voipToken: String, success successHandler: @escaping () -> Void, failure failureHandler: @escaping (Error) -> Void) {
if pushToken == PushNotificationRequestResult.FailTSOnly.rawValue || pushToken == PushNotificationRequestResult.FailBoth.rawValue {
failureHandler(OWSErrorMakeUnableToProcessServerResponseError())
} else {
successHandler()
}
}
}
class VerifyingTSAccountManager : FailingTSAccountManager {
override func verifyAccount(withCode: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) -> Void {
success()
}
override func obtainRPRegistrationToken(success: @escaping (String) -> Void, failure failureBlock: @escaping (Error) -> Void) {
failureBlock(FailedToGetRPRegistrationTokenError())
}
}
class TokenObtainingTSAccountManager : VerifyingTSAccountManager {
override func obtainRPRegistrationToken(success: @escaping (String) -> Void, failure failureBlock: @escaping (Error) -> Void) {
success("fakeRegistrationToken")
}
}
class FailingRPAccountManager : RPAccountManager {
override func register(withTsToken tsToken: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
failure(FailedToRegisterWithRedphoneError());
}
}
class SuccessfulRPAccountManager : RPAccountManager {
override func register(withTsToken tsToken: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
if tsToken == "fakeRegistrationToken" {
success()
} else {
XCTFail("Unexpected registration token:\(tsToken)")
}
}
override func registerForPushNotifications(pushToken: String, voipToken: String, success successHandler: @escaping () -> Void, failure failureHandler: @escaping (Error) -> Void) {
if pushToken == PushNotificationRequestResult.FailRPOnly.rawValue || pushToken == PushNotificationRequestResult.FailBoth.rawValue {
failureHandler(OWSErrorMakeUnableToProcessServerResponseError())
} else {
successHandler()
}
}
}
class AccountManagerTest: XCTestCase {
let tsAccountManager = FailingTSAccountManager()
let rpAccountManager = FailingRPAccountManager()
func testRegisterWhenEmptyCode() {
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should fail")
firstly {
accountManager.register(verificationCode: "")
}.then {
XCTFail("Should fail")
}.catch { error in
let nserror = error as NSError
if OWSErrorCode(rawValue: nserror.code) == OWSErrorCode.userError {
expectation.fulfill()
} else {
XCTFail("Unexpected error: \(error)")
}
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
func testRegisterWhenVerificationFails() {
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should fail")
firstly {
accountManager.register(verificationCode: "123456")
}.then {
XCTFail("Should fail")
}.catch { error in
if error is VerificationFailedError {
expectation.fulfill()
} else {
XCTFail("Unexpected error: \(error)")
}
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
func testObtainingTokenFails() {
let tsAccountManager = VerifyingTSAccountManager()
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should fail")
firstly {
accountManager.register(verificationCode: "123456")
}.then {
XCTFail("Should fail")
}.catch { error in
if error is FailedToGetRPRegistrationTokenError {
expectation.fulfill()
} else {
XCTFail("Unexpected error: \(error)")
}
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
func testRedPhoneRegistrationFails() {
let tsAccountManager = TokenObtainingTSAccountManager()
let rpAccountManager = FailingRPAccountManager()
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should fail")
firstly {
accountManager.register(verificationCode: "123456")
}.then {
XCTFail("Should fail")
}.catch { error in
if error is FailedToRegisterWithRedphoneError {
expectation.fulfill()
} else {
XCTFail("Unexpected error: \(error)")
}
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
func testSuccessfulRegistration() {
let tsAccountManager = TokenObtainingTSAccountManager()
let rpAccountManager = SuccessfulRPAccountManager()
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should succeed")
firstly {
accountManager.register(verificationCode: "123456")
}.then {
expectation.fulfill()
}.catch { error in
XCTFail("Unexpected error: \(error)")
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
func testUpdatePushTokens() {
let accountManager = AccountManager(textSecureAccountManager: tsAccountManager,
redPhoneAccountManager: rpAccountManager)
let expectation = self.expectation(description: "should fail")
accountManager.updatePushTokens(pushToken: PushNotificationRequestResult.FailTSOnly.rawValue, voipToken: "whatever").then {
XCTFail("Expected to fail.")
}.catch { error in
expectation.fulfill()
}
self.waitForExpectations(timeout: 1.0, handler: nil)
}
}

View File

@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "Signal-Bridging-Header.h"

View File

@ -22,7 +22,7 @@
- (void)testRequestToInitiate {
[SignalKeyingStorage storeString:@"shall_not_password" forKey:SAVED_PASSWORD_KEY];
[SignalKeyingStorage storeString:[@2356 stringValue] forKey:PASSWORD_COUNTER_KEY];
[TSStorageManager storePhoneNumber:@"+19027778888"];
[[TSStorageManager sharedManager] storePhoneNumber:@"+19027778888"];
HttpRequest *h =
[HttpRequest httpRequestToInitiateToRemoteNumber:[PhoneNumber phoneNumberFromE164:@"+19023334444"]];
@ -51,7 +51,7 @@
- (void)testRequestToRing {
[Environment setCurrent:testEnv];
[TSStorageManager storePhoneNumber:@"+19025555555"];
[[TSStorageManager sharedManager] storePhoneNumber:@"+19025555555"];
[SignalKeyingStorage storeString:@"shall_not_password" forKey:SAVED_PASSWORD_KEY];
[SignalKeyingStorage storeString:@"-1" forKey:PASSWORD_COUNTER_KEY];
HttpRequest *h = [HttpRequest httpRequestToRingWithSessionId:458847238];

View File

@ -10,7 +10,7 @@ if [ ! -d "Signal/src" ]; then
fi
# Search directories for .m & .h files and collect string definitions with genstrings
find $TARGETS -name "*.m" -print0 -name "*.h" -print0 | xargs -0 genstrings -o $TMP
find $TARGETS -name "*.m" -print0 -o -name "*.h" -print0 -o -name "*.swift" -print0 | xargs -0 genstrings -o $TMP
# We have to convert the old and new .strings files to UTF-8 in order to deal with them
OLDUTF8=$(iconv -f UTF-16 -t UTF-8 $STRINGFILE)