one-time carousel of changes

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 4983853dd0
commit b371e627c4

@ -13,6 +13,12 @@
34535D821E256BE9008A4747 /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 34535D811E256BE9008A4747 /* UIView+OWS.m */; }; 34535D821E256BE9008A4747 /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 34535D811E256BE9008A4747 /* UIView+OWS.m */; };
348F3A4F1E4A533900750D44 /* CallInterstitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */; }; 348F3A4F1E4A533900750D44 /* CallInterstitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */; };
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; }; 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */; };
4505C2C01E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */; };
4505C2C21E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2C11E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift */; };
4505C2C31E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2C11E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift */; };
4505C2C51E64977D00CEBF41 /* ExperienceUpgradeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2C41E64977D00CEBF41 /* ExperienceUpgradeViewController.swift */; };
4505C2C61E64977D00CEBF41 /* ExperienceUpgradeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2C41E64977D00CEBF41 /* ExperienceUpgradeViewController.swift */; };
450873C31D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */; }; 450873C31D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */; };
450873C41D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */; }; 450873C41D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */; };
450873C71D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */; }; 450873C71D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */; };
@ -82,6 +88,8 @@
45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; };
45AE48521E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; 45AE48521E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; };
45B201761DAECBFE00C461E0 /* HighlightableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B201751DAECBFE00C461E0 /* HighlightableLabel.swift */; }; 45B201761DAECBFE00C461E0 /* HighlightableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B201751DAECBFE00C461E0 /* HighlightableLabel.swift */; };
45BB93381E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */; };
45BB93391E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */; };
45BD60821DE9547E00A8F436 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45BD60811DE9547E00A8F436 /* Contacts.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 45BD60821DE9547E00A8F436 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45BD60811DE9547E00A8F436 /* Contacts.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
45BFFFA81D898AF0004A12A7 /* OWSStaleNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */; }; 45BFFFA81D898AF0004A12A7 /* OWSStaleNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */; };
45BFFFA91D898AF0004A12A7 /* OWSStaleNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */; }; 45BFFFA91D898AF0004A12A7 /* OWSStaleNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */; };
@ -612,6 +620,9 @@
348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallInterstitialViewController.swift; sourceTree = "<group>"; }; 348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallInterstitialViewController.swift; sourceTree = "<group>"; };
34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = "<group>"; }; 34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = "<group>"; };
34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = views/OWSAnyTouchGestureRecognizer.m; sourceTree = "<group>"; }; 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = views/OWSAnyTouchGestureRecognizer.m; sourceTree = "<group>"; };
4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExperienceUpgrade.swift; path = ExperienceUpgrades/ExperienceUpgrade.swift; sourceTree = "<group>"; };
4505C2C11E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExperienceUpgradeFinder.swift; sourceTree = "<group>"; };
4505C2C41E64977D00CEBF41 /* ExperienceUpgradeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExperienceUpgradeViewController.swift; sourceTree = "<group>"; };
450873C11D9D5149006B54F2 /* OWSExpirationTimerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSExpirationTimerView.h; sourceTree = "<group>"; }; 450873C11D9D5149006B54F2 /* OWSExpirationTimerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSExpirationTimerView.h; sourceTree = "<group>"; };
450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSExpirationTimerView.m; sourceTree = "<group>"; }; 450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSExpirationTimerView.m; sourceTree = "<group>"; };
450873C51D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncomingMessageCollectionViewCell.h; sourceTree = "<group>"; }; 450873C51D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIncomingMessageCollectionViewCell.h; sourceTree = "<group>"; };
@ -691,6 +702,7 @@
45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = "<group>"; }; 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = "<group>"; };
45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = "<group>"; }; 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = "<group>"; };
45B201751DAECBFE00C461E0 /* HighlightableLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightableLabel.swift; sourceTree = "<group>"; }; 45B201751DAECBFE00C461E0 /* HighlightableLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightableLabel.swift; sourceTree = "<group>"; };
45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+featureSupport.swift"; sourceTree = "<group>"; };
45BD60811DE9547E00A8F436 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 45BD60811DE9547E00A8F436 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; };
45BFFFA61D898AF0004A12A7 /* OWSStaleNotificationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSStaleNotificationObserver.h; path = Observers/OWSStaleNotificationObserver.h; sourceTree = "<group>"; }; 45BFFFA61D898AF0004A12A7 /* OWSStaleNotificationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSStaleNotificationObserver.h; path = Observers/OWSStaleNotificationObserver.h; sourceTree = "<group>"; };
45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSStaleNotificationObserver.m; path = Observers/OWSStaleNotificationObserver.m; sourceTree = "<group>"; }; 45BFFFA71D898AF0004A12A7 /* OWSStaleNotificationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSStaleNotificationObserver.m; path = Observers/OWSStaleNotificationObserver.m; sourceTree = "<group>"; };
@ -719,7 +731,7 @@
45EB32CD1D7465C900735B2E /* OWSLinkedDevicesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkedDevicesTableViewController.h; sourceTree = "<group>"; }; 45EB32CD1D7465C900735B2E /* OWSLinkedDevicesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkedDevicesTableViewController.h; sourceTree = "<group>"; };
45EB32CE1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLinkedDevicesTableViewController.m; sourceTree = "<group>"; }; 45EB32CE1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSLinkedDevicesTableViewController.m; sourceTree = "<group>"; };
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; }; 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; };
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallAudioSessionTest.swift; path = test/call/CallAudioSessionTest.swift; sourceTree = "<group>"; }; 45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSessionTest.swift; sourceTree = "<group>"; };
45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; }; 45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; };
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = "<group>"; }; 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = "<group>"; };
45F170CB1E310E22003FC1F2 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; }; 45F170CB1E310E22003FC1F2 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
@ -1311,6 +1323,15 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
4505C2BD1E648E6E00CEBF41 /* ExperienceUpgrades */ = {
isa = PBXGroup;
children = (
4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */,
4505C2C11E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift */,
);
name = ExperienceUpgrades;
sourceTree = "<group>";
};
450DF2061E0DD28D003D14BE /* UserInterface */ = { 450DF2061E0DD28D003D14BE /* UserInterface */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1589,6 +1610,7 @@
76EB041118170B33006006FC /* environment */ = { 76EB041118170B33006006FC /* environment */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4505C2BD1E648E6E00CEBF41 /* ExperienceUpgrades */,
45666F731D9BFDB9008FE134 /* Migrations */, 45666F731D9BFDB9008FE134 /* Migrations */,
B6258B311C29E2E60014138E /* NotificationsManager.h */, B6258B311C29E2E60014138E /* NotificationsManager.h */,
B6258B321C29E2E60014138E /* NotificationsManager.m */, B6258B321C29E2E60014138E /* NotificationsManager.m */,
@ -2033,6 +2055,7 @@
FC3196311A08141D0094C78E /* Settings */, FC3196311A08141D0094C78E /* Settings */,
FC3196321A08142D0094C78E /* Signals */, FC3196321A08142D0094C78E /* Signals */,
FCFD25791A1543D500F4C644 /* Signup */, FCFD25791A1543D500F4C644 /* Signup */,
4505C2C41E64977D00CEBF41 /* ExperienceUpgradeViewController.swift */,
); );
name = "View Controllers"; name = "View Controllers";
path = "view controllers"; path = "view controllers";
@ -2212,6 +2235,7 @@
B660F6731C29867F00687D6E /* call */ = { B660F6731C29867F00687D6E /* call */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */,
456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */, 456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */,
B660F6741C29867F00687D6E /* RecentCallTest.m */, B660F6741C29867F00687D6E /* RecentCallTest.m */,
); );
@ -2492,7 +2516,6 @@
B660F66C1C29867F00687D6E /* test */, B660F66C1C29867F00687D6E /* test */,
D221A094169C9E5E00537ABF /* Supporting Files */, D221A094169C9E5E00537ABF /* Supporting Files */,
B66DBF4919D5BBC8006EA940 /* Images.xcassets */, B66DBF4919D5BBC8006EA940 /* Images.xcassets */,
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */,
); );
path = Signal; path = Signal;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2656,6 +2679,7 @@
EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */, EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */,
344F2F651E57A932000D9322 /* UIViewController+OWS.h */, 344F2F651E57A932000D9322 /* UIViewController+OWS.h */,
344F2F661E57A932000D9322 /* UIViewController+OWS.m */, 344F2F661E57A932000D9322 /* UIViewController+OWS.m */,
45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */,
); );
name = "UI Categories"; name = "UI Categories";
path = ..; path = ..;
@ -3071,6 +3095,7 @@
76EB061218170B33006006FC /* LoggingUtil.m in Sources */, 76EB061218170B33006006FC /* LoggingUtil.m in Sources */,
76EB060E18170B33006006FC /* DecayingSampleEstimator.m in Sources */, 76EB060E18170B33006006FC /* DecayingSampleEstimator.m in Sources */,
340757C21E5602D6001F15DD /* AttachmentSharing.m in Sources */, 340757C21E5602D6001F15DD /* AttachmentSharing.m in Sources */,
4505C2C21E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift in Sources */,
76EB05BA18170B33006006FC /* CommitPacket.m in Sources */, 76EB05BA18170B33006006FC /* CommitPacket.m in Sources */,
344F2F671E57A932000D9322 /* UIViewController+OWS.m in Sources */, 344F2F671E57A932000D9322 /* UIViewController+OWS.m in Sources */,
76EB060218170B33006006FC /* InitiatorSessionDescriptor.m in Sources */, 76EB060218170B33006006FC /* InitiatorSessionDescriptor.m in Sources */,
@ -3093,6 +3118,7 @@
4531C9C41DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.m in Sources */, 4531C9C41DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.m in Sources */,
4516E3FF1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */, 4516E3FF1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */,
76EB05A818170B33006006FC /* RtpSocket.m in Sources */, 76EB05A818170B33006006FC /* RtpSocket.m in Sources */,
4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */,
45387B041E36D650005D00B3 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */, 45387B041E36D650005D00B3 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */,
E197B61818BBEC1A00F073E5 /* RemoteIOAudio.m in Sources */, E197B61818BBEC1A00F073E5 /* RemoteIOAudio.m in Sources */,
B67ADDC41989FF8700E1A773 /* RPServerRequestsManager.m in Sources */, B67ADDC41989FF8700E1A773 /* RPServerRequestsManager.m in Sources */,
@ -3184,6 +3210,7 @@
E197B61118BBEC1A00F073E5 /* AudioProcessor.m in Sources */, E197B61118BBEC1A00F073E5 /* AudioProcessor.m in Sources */,
FCAC964019FEF99A0046DFC5 /* InboxTableViewCell.m in Sources */, FCAC964019FEF99A0046DFC5 /* InboxTableViewCell.m in Sources */,
76EB05EA18170B33006006FC /* CallProgress.m in Sources */, 76EB05EA18170B33006006FC /* CallProgress.m in Sources */,
4505C2C51E64977D00CEBF41 /* ExperienceUpgradeViewController.swift in Sources */,
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
FCFA64B41A24F3880007FB87 /* UIColor+OWS.m in Sources */, FCFA64B41A24F3880007FB87 /* UIColor+OWS.m in Sources */,
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */, 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
@ -3242,6 +3269,7 @@
45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */, 45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */,
45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */, 45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */,
B63761EE19E1FBE8005735D1 /* HttpRequestUtil.m in Sources */, B63761EE19E1FBE8005735D1 /* HttpRequestUtil.m in Sources */,
45BB93381E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */,
458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */, 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */,
451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */, 451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */,
76EB05B618170B33006006FC /* MasterSecret.m in Sources */, 76EB05B618170B33006006FC /* MasterSecret.m in Sources */,
@ -3305,6 +3333,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4505C2C31E648F7A00CEBF41 /* ExperienceUpgradeFinder.swift in Sources */,
B660F7001C29988E00687D6E /* AppAudioManager.m in Sources */, B660F7001C29988E00687D6E /* AppAudioManager.m in Sources */,
B660F7011C29988E00687D6E /* AudioRouter.m in Sources */, B660F7011C29988E00687D6E /* AudioRouter.m in Sources */,
B660F7021C29988E00687D6E /* AudioPacker.m in Sources */, B660F7021C29988E00687D6E /* AudioPacker.m in Sources */,
@ -3346,6 +3375,7 @@
B660F71D1C29988E00687D6E /* LocalizableText.m in Sources */, B660F71D1C29988E00687D6E /* LocalizableText.m in Sources */,
B660F71F1C29988E00687D6E /* PropertyListPreferences.m in Sources */, B660F71F1C29988E00687D6E /* PropertyListPreferences.m in Sources */,
B660F7201C29988E00687D6E /* Release.m in Sources */, B660F7201C29988E00687D6E /* Release.m in Sources */,
45BB93391E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */,
B660F7211C29988E00687D6E /* SignalKeyingStorage.m in Sources */, B660F7211C29988E00687D6E /* SignalKeyingStorage.m in Sources */,
B660F7221C29988E00687D6E /* VersionMigrations.m in Sources */, B660F7221C29988E00687D6E /* VersionMigrations.m in Sources */,
B660F7231C29988E00687D6E /* DnsManager.m in Sources */, B660F7231C29988E00687D6E /* DnsManager.m in Sources */,
@ -3522,11 +3552,13 @@
B660F6CD1C29868000687D6E /* UdpSocketTest.m in Sources */, B660F6CD1C29868000687D6E /* UdpSocketTest.m in Sources */,
B660F6DD1C29868000687D6E /* ObservableTest.m in Sources */, B660F6DD1C29868000687D6E /* ObservableTest.m in Sources */,
B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */, B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */,
4505C2C01E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */,
B660F6C61C29868000687D6E /* MasterSecretTest.m in Sources */, B660F6C61C29868000687D6E /* MasterSecretTest.m in Sources */,
B660F6D91C29868000687D6E /* CyclicalBufferTest.m in Sources */, B660F6D91C29868000687D6E /* CyclicalBufferTest.m in Sources */,
B660F6DC1C29868000687D6E /* FutureUtilTest.m in Sources */, B660F6DC1C29868000687D6E /* FutureUtilTest.m in Sources */,
450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */, 450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */,
B660F6CA1C29868000687D6E /* LowLatencyConnectorTest.m in Sources */, B660F6CA1C29868000687D6E /* LowLatencyConnectorTest.m in Sources */,
4505C2C61E64977D00CEBF41 /* ExperienceUpgradeViewController.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "signal-answer.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "signal-answer@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "signal-answer@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "signal-video-splash.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "signal-video-splash@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "signal-video-splash@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

@ -0,0 +1,11 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
extension UIDevice {
var supportsCallKit: Bool {
return ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0))
}
}

@ -49,4 +49,7 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value);
- (void)addBorderWithColor:(UIColor *)color; - (void)addBorderWithColor:(UIColor *)color;
- (void)addRedBorder; - (void)addRedBorder;
// Add red border to self, and all subviews recursively.
- (void)addRedBorderRecursively;
@end @end

@ -166,4 +166,12 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
[self addBorderWithColor:[UIColor redColor]]; [self addBorderWithColor:[UIColor redColor]];
} }
- (void)addRedBorderRecursively
{
[self addRedBorder];
for (UIView *subview in self.subviews) {
[subview addRedBorderRecursively];
}
}
@end @end

@ -0,0 +1,38 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
class ExperienceUpgradeFinder: NSObject {
public let TAG = "[ExperienceUpgradeFinder]"
// Keep these ordered by increasing uniqueId.
private var allExperienceUpgrades: [ExperienceUpgrade] {
var upgrades = [ExperienceUpgrade(uniqueId: "001",
title: NSLocalizedString("UPGRADE_EXPERIENCE_VIDEO_TITLE", comment: "Header for upgrade experience"),
body: NSLocalizedString("UPGRADE_EXPERIENCE_VIDEO_DESCRIPTION", comment: "Description of video calling to upgrading (existing) users"),
image: #imageLiteral(resourceName: "introductory_splash_video_calling"))]
if UIDevice.current.supportsCallKit {
upgrades.append(ExperienceUpgrade(uniqueId: "002",
title: NSLocalizedString("UPGRADE_EXPERIENCE_CALLKIT_TITLE", comment: "Header for upgrade experience"),
body: NSLocalizedString("UPGRADE_EXPERIENCE_CALLKIT_DESCRIPTION", comment: "Description of CallKit to upgrading (existing) users"),
image: #imageLiteral(resourceName: "introductory_splash_callkit")))
}
return upgrades
}
// MARK: - Instance Methods
public func allUnseen(transaction: YapDatabaseReadTransaction) -> [ExperienceUpgrade] {
return allExperienceUpgrades.filter { ExperienceUpgrade.fetch(withUniqueID: $0.uniqueId, transaction: transaction) == nil }
}
public func markAllAsSeen(transaction: YapDatabaseReadWriteTransaction) {
Logger.info("\(TAG) marking experience upgrades as seen")
allExperienceUpgrades.forEach { $0.save(with: transaction) }
}
}

@ -0,0 +1,69 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
class ExperienceUpgrade: TSYapDatabaseObject {
let title: String
let body: String
let image: UIImage?
var seenAt: Date?
required init(uniqueId: String, title: String, body: String, image: UIImage) {
self.title = title
self.body = body
self.image = image
super.init(uniqueId: uniqueId)
}
override required init(uniqueId: String) {
// This is the unfortunate seam between strict swift and fast-and-loose objc
// we can't leave these properties nil, since we really "don't know" that the superclass
// will assign them.
self.title = "New Feature"
self.body = "Bug fixes and performance improvements."
self.image = nil
super.init(uniqueId: uniqueId)
}
required init!(coder: NSCoder!) {
// This is the unfortunate seam between strict swift and fast-and-loose objc
// we can't leave these properties nil, since we really "don't know" that the superclass
// will assign them.
self.title = "New Feature"
self.body = "Bug fixes and performance improvements."
self.image = nil
super.init(coder: coder)
}
required init(dictionary dictionaryValue: [AnyHashable : Any]!) throws {
// This is the unfortunate seam between strict swift and fast-and-loose objc
// we can't leave these properties nil, since we really "don't know" that the superclass
// will assign them.
self.title = "New Feature"
self.body = "Bug fixes and performance improvements."
self.image = nil
try super.init(dictionary: dictionaryValue)
}
override class func storageBehaviorForProperty(withKey propertyKey: String) -> MTLPropertyStorage {
// These exist in a hardcoded set - no need to save them, plus it allows us to
// update copy/image down the line if there was a typo and we want to re-expose
// these models in a "change log" archive.
if propertyKey == "title" || propertyKey == "body" || propertyKey == "image" {
return MTLPropertyStorageNone
} else if propertyKey == "uniqueId" || propertyKey == "seenAt" {
return super.storageBehaviorForProperty(withKey: propertyKey)
} else {
// Being conservative here in case we rename a property.
assertionFailure("unknown property \(propertyKey)")
return super.storageBehaviorForProperty(withKey: propertyKey)
}
}
func markAsSeen(transaction: YapDatabaseReadWriteTransaction) {
self.seenAt = Date()
super.save(with: transaction)
}
}

@ -910,7 +910,7 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R
return return
} else if !ignoreNag && } else if !ignoreNag &&
call.direction == .incoming && call.direction == .incoming &&
supportsCallKit() && UIDevice.current.supportsCallKit &&
(!Environment.getCurrent().preferences.isCallKitEnabled() || (!Environment.getCurrent().preferences.isCallKitEnabled() ||
Environment.getCurrent().preferences.isCallKitPrivacyEnabled()) { Environment.getCurrent().preferences.isCallKitPrivacyEnabled()) {
@ -948,13 +948,7 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R
self.dismiss(animated: false, completion:completion) self.dismiss(animated: false, completion:completion)
} }
} }
// MARK: - Util
private func supportsCallKit() -> Bool {
return ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0))
}
// MARK: - CallServiceObserver // MARK: - CallServiceObserver
internal func didUpdateCall(call: SignalCall?) { internal func didUpdateCall(call: SignalCall?) {

@ -0,0 +1,292 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
class ExperienceUpgradeViewController: UIViewController, UIScrollViewDelegate {
let TAG = "[ExperienceUpgradeViewController]"
private let experienceUpgrades: [ExperienceUpgrade]
private var nextButton: UIButton!
private var previousButton: UIButton!
// MARK: - Initializers
required init(experienceUpgrades: [ExperienceUpgrade]) {
self.experienceUpgrades = experienceUpgrades
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable, message:"unavailable, use initWithExperienceUpgrade instead")
required init?(coder aDecoder: NSCoder) {
assert(false)
// This should never happen, but so as not to explode we give some bogus data
self.experienceUpgrades = [ExperienceUpgrade()]
super.init(coder: aDecoder)
}
// MARK: - View lifecycle
override func viewDidLoad() {
super.viewDidLoad()
addDismissGesture()
showCurrentSlide()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Avoid any possible vertical scrolling, which feels weird for carousel which should only swipe left/right
// if our carousel content is properly sized to be <= the carousel height. When written this wasn't be an issue,
// but it would be easy to introduce a small layout issue in the future which oversizes the content.
self.carouselView.contentSize = CGSize(width: self.carouselView.contentSize.width, // use actual content width
height: self.carouselView.frame.size.height) // but crop height to frame
}
override func loadView() {
self.view = UIView()
view.backgroundColor = UIColor.white
let splashView = UIView()
view.addSubview(splashView)
splashView.autoPinEdgesToSuperviewEdges()
let carouselView = UIScrollView()
carouselView.delegate = self
self.carouselView = carouselView
splashView.addSubview(carouselView)
self.carouselView.isPagingEnabled = true
carouselView.showsHorizontalScrollIndicator = false
carouselView.showsVerticalScrollIndicator = false
carouselView.bounces = false
// CarouselView layout
carouselView.autoPinEdge(toSuperviewEdge: .top)
carouselView.autoPinEdge(toSuperviewEdge: .left)
carouselView.autoPinEdge(toSuperviewEdge: .right)
// Build slides for carousel
var previousSlideView: UIView?
for experienceUpgrade in experienceUpgrades {
let slideView = buildSlideView(header: experienceUpgrade.title, body: experienceUpgrade.body, image: experienceUpgrade.image)
carouselView.addSubview(slideView)
slideView.autoPinEdge(toSuperviewEdge: .top, withInset: ScaleFromIPhone5(10))
slideView.autoPinEdge(toSuperviewEdge: .bottom)
slideView.autoMatch(.width, to: .width, of: carouselView)
// pin first slide to the superview
if previousSlideView == nil {
slideView.autoPinEdge(toSuperviewEdge: .left)
} else {
// pin any subsequent slide to the preveding slide
slideView.autoPinEdge(.left, to: .right, of: previousSlideView!)
}
previousSlideView = slideView
}
// we should never be presenting a blank slideshow.
// but if so, we don't want to crash in prod.
assert(previousSlideView != nil)
// ping the last slide to the superview right.
previousSlideView?.autoPinEdge(toSuperviewEdge: .right)
// Previous button
// Lightening the arrows' color to balance their heavy stroke with the thinner text on the page.
let arrowButtonColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1)
let previousButton = UIButton()
self.previousButton = previousButton
splashView.addSubview(previousButton)
previousButton.isUserInteractionEnabled = true
previousButton.setTitleColor(arrowButtonColor, for: .normal)
previousButton.accessibilityLabel = NSLocalizedString("UPGRADE_CAROUSEL_PREVIOUS_BUTTON", comment: "accessibility label for arrow in slideshow")
previousButton.setTitle("", for: .normal)
previousButton.titleLabel?.font = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5To7Plus(24, 48))
previousButton.addTarget(self, action:#selector(didTapPreviousButton), for: .touchUpInside)
// Previous button layout
previousButton.autoPinEdge(toSuperviewEdge: .left)
let arrowButtonInset = ScaleFromIPhone5(200)
previousButton.autoPinEdge(toSuperviewEdge: .top, withInset: arrowButtonInset)
// Next button
let nextButton = UIButton()
self.nextButton = nextButton
splashView.addSubview(nextButton)
nextButton.isUserInteractionEnabled = true
nextButton.setTitleColor(arrowButtonColor, for: .normal)
nextButton.accessibilityLabel = NSLocalizedString("UPGRADE_CAROUSEL_NEXT_BUTTON", comment: "accessibility label for arrow in slideshow")
nextButton.setTitle("", for: .normal)
nextButton.titleLabel?.font = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5To7Plus(24, 48))
nextButton.addTarget(self, action:#selector(didTapNextButton), for: .touchUpInside)
// Next button layout
nextButton.autoPinEdge(toSuperviewEdge: .right)
nextButton.autoPinEdge(toSuperviewEdge: .top, withInset: arrowButtonInset)
// Dismiss button
let dismissButton = UIButton()
splashView.addSubview(dismissButton)
dismissButton.setTitle(NSLocalizedString("DISMISS_BUTTON_TEXT", comment: ""), for: .normal)
dismissButton.setTitleColor(UIColor.ows_materialBlue(), for: .normal)
dismissButton.isUserInteractionEnabled = true
dismissButton.addTarget(self, action:#selector(didTapDismissButton), for: .touchUpInside)
// Dismiss button layout
dismissButton.autoPinWidthToSuperview()
dismissButton.autoPinEdge(.top, to: .bottom, of: carouselView, withOffset: ScaleFromIPhone5(16))
dismissButton.autoPinEdge(toSuperviewEdge: .bottom, withInset: ScaleFromIPhone5(32))
}
private func buildSlideView(header: String, body: String, image: UIImage?) -> UIView {
Logger.debug("\(TAG) in \(#function)")
let containerView = UIView()
let headerView = UIView()
containerView.addSubview(headerView)
headerView.backgroundColor = UIColor.ows_materialBlue()
headerView.autoPinWidthToSuperview()
headerView.autoPinEdge(toSuperviewEdge: .top, withInset: -16)
headerView.autoSetDimension(.height, toSize: ScaleFromIPhone5(100))
// Title label
let titleLabel = UILabel()
headerView.addSubview(titleLabel)
titleLabel.text = header
titleLabel.textAlignment = .center
titleLabel.font = UIFont.ows_regularFont(withSize: ScaleFromIPhone5To7Plus(26, 32))
titleLabel.textColor = UIColor.white
titleLabel.minimumScaleFactor = 0.5
titleLabel.adjustsFontSizeToFitWidth = true;
// Title label layout
titleLabel.autoPinWidthToSuperview(withMargin: ScaleFromIPhone5To7Plus(16, 24))
titleLabel.autoPinEdge(toSuperviewEdge: .bottom, withInset: ScaleFromIPhone5To7Plus(24, 32))
let slideView = UIView()
containerView.addSubview(slideView)
let containerPadding = ScaleFromIPhone5To7Plus(12, 24)
slideView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: containerPadding, left: containerPadding, bottom: containerPadding, right: containerPadding))
// Body label
let bodyLabel = UILabel()
slideView.addSubview(bodyLabel)
bodyLabel.text = body
bodyLabel.font = UIFont.ows_lightFont(withSize: ScaleFromIPhone5To7Plus(18, 22))
bodyLabel.textColor = UIColor.black
bodyLabel.numberOfLines = 0
bodyLabel.textAlignment = .center
// Body label layout
bodyLabel.autoPinWidthToSuperview()
bodyLabel.sizeToFit()
// Image
let imageView = UIImageView(image: image)
slideView.addSubview(imageView)
imageView.contentMode = .scaleAspectFit
// Image layout
imageView.autoPinWidthToSuperview()
imageView.autoSetDimension(.height, toSize: ScaleFromIPhone5To7Plus(200, 280))
imageView.autoPinEdge(.top, to: .bottom, of: headerView, withOffset: ScaleFromIPhone5To7Plus(24, 32))
imageView.autoPinEdge(.bottom, to: .top, of: bodyLabel, withOffset: -ScaleFromIPhone5To7Plus(24, 32))
return containerView
}
private func addDismissGesture() {
let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleDismissGesture))
swipeGesture.direction = .down
view.addGestureRecognizer(swipeGesture)
}
// MARK: Carousel
private var carouselView: UIScrollView!
private var currentSlideIndex = 0
private func showNextSlide() {
guard hasNextSlide() else {
Logger.debug("\(TAG) no next slide to show")
return;
}
currentSlideIndex += 1
showCurrentSlide()
}
private func showPreviousSlide() {
guard hasPreviousSlide() else {
Logger.debug("\(TAG) no previous slide to show")
return
}
currentSlideIndex -= 1
showCurrentSlide()
}
private func hasPreviousSlide() -> Bool {
return currentSlideIndex > 0
}
private func hasNextSlide() -> Bool {
return currentSlideIndex < experienceUpgrades.count - 1
}
private func updateSlideControls() {
self.nextButton.isHidden = !hasNextSlide()
self.previousButton.isHidden = !hasPreviousSlide()
}
private func showCurrentSlide() {
Logger.debug("\(TAG) showing slide: \(currentSlideIndex)")
updateSlideControls()
// update the scroll view to the appropriate page
let bounds = carouselView.bounds
let point = CGPoint(x: bounds.width * CGFloat(currentSlideIndex), y: 0)
let pageBounds = CGRect(origin: point, size: bounds.size)
carouselView.scrollRectToVisible(pageBounds, animated: true)
}
// MARK: - Actions
func didTapNextButton(sender: UIButton) {
Logger.debug("\(TAG) in \(#function)")
showNextSlide()
}
func didTapPreviousButton(sender: UIButton) {
Logger.debug("\(TAG) in \(#function)")
showPreviousSlide()
}
func didTapDismissButton(sender: UIButton) {
Logger.debug("\(TAG) in \(#function)")
self.dismiss(animated: true)
}
func handleDismissGesture(sender: AnyObject) {
Logger.debug("\(TAG) in \(#function)")
self.dismiss(animated: true)
}
// MARK: - ScrollViewDelegate
// Update the slider controls to reflect which page we think we'll end up on.
// we use WillEndDragging instead of (e.g.) didEndDecelerating, else the switch feels too late.
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = scrollView.frame.size.width
let page = floor(targetContentOffset.pointee.x / pageWidth)
currentSlideIndex = Int(page)
updateSlideControls()
}
}

@ -136,9 +136,9 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
case PrivacySettingsTableViewControllerSectionIndexCalling: case PrivacySettingsTableViewControllerSectionIndexCalling:
return 1; return 1;
case PrivacySettingsTableViewControllerSectionIndexCallKitEnabled: case PrivacySettingsTableViewControllerSectionIndexCallKitEnabled:
return self.supportsCallKit ? 1 : 0; return [UIDevice currentDevice].supportsCallKit ? 1 : 0;
case PrivacySettingsTableViewControllerSectionIndexCallKitPrivacy: case PrivacySettingsTableViewControllerSectionIndexCallKitPrivacy:
return (self.supportsCallKit && [[Environment getCurrent].preferences isCallKitEnabled]) ? 1 : 0; return ([UIDevice currentDevice].supportsCallKit && [[Environment getCurrent].preferences isCallKitEnabled]) ? 1 : 0;
case PrivacySettingsTableViewControllerSectionIndexHistoryLog: case PrivacySettingsTableViewControllerSectionIndexHistoryLog:
return 1; return 1;
case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange:
@ -157,11 +157,11 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
return NSLocalizedString(@"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL", return NSLocalizedString(@"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL",
@"User settings section footer, a detailed explanation"); @"User settings section footer, a detailed explanation");
case PrivacySettingsTableViewControllerSectionIndexCallKitEnabled: case PrivacySettingsTableViewControllerSectionIndexCallKitEnabled:
return (self.supportsCallKit return ([UIDevice currentDevice].supportsCallKit
? NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer.") ? NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer.")
: nil); : nil);
case PrivacySettingsTableViewControllerSectionIndexCallKitPrivacy: case PrivacySettingsTableViewControllerSectionIndexCallKitPrivacy:
return ((self.supportsCallKit && [[Environment getCurrent].preferences isCallKitEnabled]) return (([UIDevice currentDevice].supportsCallKit && [[Environment getCurrent].preferences isCallKitEnabled])
? NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION", ? NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION",
@"Explanation of the 'CallKit Privacy` preference.") @"Explanation of the 'CallKit Privacy` preference.")
: nil); : nil);
@ -274,13 +274,6 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
[[Environment getCurrent].preferences setIsCallKitPrivacyEnabled:!sender.isOn]; [[Environment getCurrent].preferences setIsCallKitPrivacyEnabled:!sender.isOn];
} }
#pragma mark - Util
- (BOOL)supportsCallKit
{
return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(10, 0);
}
#pragma mark - Log util #pragma mark - Log util
+ (NSString *)tag + (NSString *)tag

@ -39,8 +39,12 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
@property (nonatomic) long inboxCount; @property (nonatomic) long inboxCount;
@property (nonatomic, retain) UISegmentedControl *segmentedControl; @property (nonatomic, retain) UISegmentedControl *segmentedControl;
@property (nonatomic, strong) id previewingContext; @property (nonatomic, strong) id previewingContext;
// Dependencies
@property (nonatomic, readonly, strong) AccountManager *accountManager; @property (nonatomic, readonly, strong) AccountManager *accountManager;
@property (nonatomic, readonly) OWSContactsManager *contactsManager; @property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) ExperienceUpgradeFinder *experienceUpgradeFinder;
@property (nonatomic, readonly) TSMessagesManager *messagesManager; @property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly, strong) OWSMessageSender *messageSender; @property (nonatomic, readonly, strong) OWSMessageSender *messageSender;
@ -78,6 +82,7 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
_contactsManager = [Environment getCurrent].contactsManager; _contactsManager = [Environment getCurrent].contactsManager;
_messagesManager = [TSMessagesManager sharedManager]; _messagesManager = [TSMessagesManager sharedManager];
_messageSender = [Environment getCurrent].messageSender; _messageSender = [Environment getCurrent].messageSender;
_experienceUpgradeFinder = [ExperienceUpgradeFinder new];
} }
- (void)awakeFromNib - (void)awakeFromNib
@ -304,10 +309,18 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
- (void)viewDidAppear:(BOOL)animated { - (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]; [super viewDidAppear:animated];
if (self.newlyRegisteredUser) { if (self.newlyRegisteredUser) {
[self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
[self.experienceUpgradeFinder markAllAsSeenWithTransaction:transaction];
}];
[self didAppearForNewlyRegisteredUser]; [self didAppearForNewlyRegisteredUser];
} else {
[self displayAnyUnseenUpgradeExperience];
} }
} }
#pragma mark - startup
- (void)didAppearForNewlyRegisteredUser - (void)didAppearForNewlyRegisteredUser
{ {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
@ -341,6 +354,25 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
} }
} }
- (void)displayAnyUnseenUpgradeExperience
{
AssertIsOnMainThread();
__block NSArray<ExperienceUpgrade *> *unseenUpgrades;
[self.editingDbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
unseenUpgrades = [self.experienceUpgradeFinder allUnseenWithTransaction:transaction];
}];
if (unseenUpgrades.count > 0) {
ExperienceUpgradeViewController *experienceUpgradeViewController = [[ExperienceUpgradeViewController alloc] initWithExperienceUpgrades:unseenUpgrades];
[self presentViewController:experienceUpgradeViewController animated:YES completion:^{
[self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
[self.experienceUpgradeFinder markAllAsSeenWithTransaction:transaction];
}];
}];
}
}
- (void)ensureNotificationsUpToDate - (void)ensureNotificationsUpToDate
{ {
OWSSyncPushTokensJob *syncPushTokensJob = OWSSyncPushTokensJob *syncPushTokensJob =

@ -791,10 +791,10 @@
"SETTINGS_BUTTON_ACCESSIBILITY" = "Settings"; "SETTINGS_BUTTON_ACCESSIBILITY" = "Settings";
/* Table cell label */ /* Table cell label */
"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE" = "Hide IP Address"; "SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE" = "Always Relay Calls";
/* User settings section footer, a detailed explanation */ /* User settings section footer, a detailed explanation */
"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL" = "Hiding your IP address during audio and video calls will decrease call quality."; "SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL" = "Relay all calls through the Signal server to avoid revealing your IP address to your contact. Enabling will reduce call quality.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_CLEAR_HISTORY" = "Clear History Logs"; "SETTINGS_CLEAR_HISTORY" = "Clear History Logs";
@ -836,7 +836,7 @@
"SETTINGS_PRIVACY_CALLKIT_PRIVACY_TITLE" = "Show Names & Numbers"; "SETTINGS_PRIVACY_CALLKIT_PRIVACY_TITLE" = "Show Names & Numbers";
/* Short table cell label */ /* Short table cell label */
"SETTINGS_PRIVACY_CALLKIT_TITLE" = "Use CallKit"; "SETTINGS_PRIVACY_CALLKIT_TITLE" = "iOS Call Integration";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_PRIVACY_TITLE" = "Privacy"; "SETTINGS_PRIVACY_TITLE" = "Privacy";
@ -848,10 +848,10 @@
"SETTINGS_SCREEN_SECURITY" = "Enable Screen Security"; "SETTINGS_SCREEN_SECURITY" = "Enable Screen Security";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_SCREEN_SECURITY_DETAIL" = "Prevents Signal previews from appearing in the app switcher."; "SETTINGS_SCREEN_SECURITY_DETAIL" = "Prevent Signal previews from appearing in the app switcher.";
/* Settings table section footer. */ /* Settings table section footer. */
"SETTINGS_SECTION_CALL_KIT_DESCRIPTION" = "CallKit allows you to answer calls directly from your lockscreen. Be aware that when using CallKit, Apple syncs some call metadata to your iCloud account."; "SETTINGS_SECTION_CALL_KIT_DESCRIPTION" = "Show Signal calls on your lock screen and in the system's call history. If iCloud is enabled, call history will be shared with Apple.";
/* Explanation of the 'CallKit Privacy` preference. */ /* Explanation of the 'CallKit Privacy` preference. */
"SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION" = "If you show the names and phone numbers of incoming callers in CallKit, this information will appear in your phone's call history and will be synced to your iCloud account."; "SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION" = "If you show the names and phone numbers of incoming callers in CallKit, this information will appear in your phone's call history and will be synced to your iCloud account.";
@ -949,6 +949,24 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"UPDATE_BUTTON_TITLE" = "Update"; "UPDATE_BUTTON_TITLE" = "Update";
/* accessibility label for arrow in slideshow */
"UPGRADE_CAROUSEL_NEXT_BUTTON" = "Show next";
/* accessibility label for arrow in slideshow */
"UPGRADE_CAROUSEL_PREVIOUS_BUTTON" = "Show previous";
/* Description of CallKit to upgrading (existing) users */
"UPGRADE_EXPERIENCE_CALLKIT_DESCRIPTION" = "Answering calls from your lockscreen is easy and private, since by default we anonymize your caller.\n\n Read more in your privacy settings.";
/* Header for upgrade experience */
"UPGRADE_EXPERIENCE_CALLKIT_TITLE" = "Just Swipe to Answer";
/* Description of video calling to upgrading (existing) users */
"UPGRADE_EXPERIENCE_VIDEO_DESCRIPTION" = "Signal now supports secure video calling. Just start a call like normal, tap the camera button, and wave hello.";
/* Header for upgrade experience */
"UPGRADE_EXPERIENCE_VIDEO_TITLE" = "Hello Secure Video Calls!";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"Upgrading Signal ..." = "Upgrading Signal ..."; "Upgrading Signal ..." = "Upgrading Signal ...";

Loading…
Cancel
Save