Disappearing Messages

* Per thread settings menu accessed by tapping on thread title

  This removed the toggle-phone behavior. You'll be able to see the phone
  number in the settings table view.

  This removed the "add contact" functionality, although it was already
  broken for ios>=9 (which is basically everybody).

  The group actions menu was absorbed into this screen

* Added a confirm alert to leave group (fixes #938)

* New Translation Strings
* Extend "Add People" label to fit translations.
* resolved issues with translations not fitting in group menu

* Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter.

* Can delete info messages

  Follow the JSQMVC pattern and put UIResponder-able content in the
  messageBubbleContainer. This gives us more functionality *and* allows us
  to delete some code. yay!

  It's still not yet possible to delete phone messages. =(

* Fixed some compiler warnings.

* xcode8 touching storyboard. So long xcode7!

* Fixup multiline info messages.

  We were seeing info messages like "You set disappearing message timer to
  10" instead of "You set disappearing message timer to 10 seconds."

  Admittedly this isn't a very good fix, as now one liners feel like they
  have too much padding.

   If the message is well over one line, we were wrapping properly, but
  there's a problem when the message is *just barely* two lines, the cell
  height grows, but the label still thinks it's just one line (as evinced
  by the one line appearing in the center of the label frame. The result
  being that the last word of the label is cropped.

* Disable group actions after leaving group.

// FREEBIE
This commit is contained in:
Michael Kirk 2016-09-21 08:37:51 -04:00
parent 48336b6c53
commit ee0cce75e8
117 changed files with 2710 additions and 1079 deletions

View File

@ -1,7 +1,7 @@
language: objective-c language: objective-c
cache: cocoapods # pod install somtimes takes >20 minutes, so lets cache this cache: cocoapods # pod install somtimes takes >20 minutes, so lets cache this
osx_image: xcode7.3 osx_image: xcode8
before_install: before_install:
- brew update # we may not be running the latest version so always update - brew update # we may not be running the latest version so always update
@ -16,5 +16,8 @@ script:
- | - |
set -o pipefail set -o pipefail
# default xctool was hanging. see https://github.com/travis-ci/travis-ci/issues/3986 # default xctool was hanging. see https://github.com/travis-ci/travis-ci/issues/3986
xcodebuild -workspace Signal.xcworkspace -scheme Signal -sdk iphonesimulator build test | xcpretty xcodebuild -workspace Signal.xcworkspace -scheme Signal \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' \
build test | xcpretty

View File

@ -39,8 +39,8 @@
#error This class requires automatic reference counting #error This class requires automatic reference counting
#endif #endif
// Unknown diagnostic
#pragma clang diagnostic ignored "-Wreceiver-is-weak" // #pragma clang diagnostic ignored "-Wreceiver-is-weak"
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak" #pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
#pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis" #pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis"
#pragma clang diagnostic ignored "-Wdirect-ivar-access" #pragma clang diagnostic ignored "-Wdirect-ivar-access"

View File

@ -3,7 +3,7 @@ source 'https://github.com/CocoaPods/Specs.git'
target 'Signal' do target 'Signal' do
pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git' pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git'
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git', branch: 'new-fingerprint-format' pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git', branch: 'release/2.6'
#pod 'SignalServiceKit', path: '../SignalServiceKit' #pod 'SignalServiceKit', path: '../SignalServiceKit'
pod 'OpenSSL', '~> 1.0.208' pod 'OpenSSL', '~> 1.0.208'
pod 'PastelogKit', '~> 1.3' pod 'PastelogKit', '~> 1.3'

View File

@ -122,20 +122,20 @@ DEPENDENCIES:
- OpenSSL (~> 1.0.208) - OpenSSL (~> 1.0.208)
- PastelogKit (~> 1.3) - PastelogKit (~> 1.3)
- SCWaveformView (~> 1.0) - SCWaveformView (~> 1.0)
- SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`, branch `new-fingerprint-format`) - SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`, branch `release/2.6`)
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`) - SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
- ZXingObjC - ZXingObjC
EXTERNAL SOURCES: EXTERNAL SOURCES:
SignalServiceKit: SignalServiceKit:
:branch: new-fingerprint-format :branch: release/2.6
:git: https://github.com/WhisperSystems/SignalServiceKit.git :git: https://github.com/WhisperSystems/SignalServiceKit.git
SocketRocket: SocketRocket:
:git: https://github.com/facebook/SocketRocket.git :git: https://github.com/facebook/SocketRocket.git
CHECKOUT OPTIONS: CHECKOUT OPTIONS:
SignalServiceKit: SignalServiceKit:
:commit: 2b612e9ab72b427b310b125b1dc82eef1d3f85ec :commit: a277fbfacb10599ce609e625e599a9903f8d0ebf
:git: https://github.com/WhisperSystems/SignalServiceKit.git :git: https://github.com/WhisperSystems/SignalServiceKit.git
SocketRocket: SocketRocket:
:commit: 41b57bb2fc292a814f758441a05243eb38457027 :commit: 41b57bb2fc292a814f758441a05243eb38457027
@ -167,6 +167,6 @@ SPEC CHECKSUMS:
YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f
ZXingObjC: bf15b3814f7a105b6d99f47da2333c93a063650a ZXingObjC: bf15b3814f7a105b6d99f47da2333c93a063650a
PODFILE CHECKSUM: d4204cf787649f9512dc74e5844f48d2570d5b2e PODFILE CHECKSUM: 1e76310fe364da5f11d50ef76ccf13714b52926b
COCOAPODS: 1.0.1 COCOAPODS: 1.0.1

View File

@ -9,12 +9,20 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
0DD55B166906AF3368995978 /* libPods-Signal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80CD5E19DD23200E7926EEA7 /* libPods-Signal.a */; }; 0DD55B166906AF3368995978 /* libPods-Signal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80CD5E19DD23200E7926EEA7 /* libPods-Signal.a */; };
30209C98DABCE82064B4EAF5 /* libPods-SignalTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A33D3C7EB4B17BDBD47F0FCC /* libPods-SignalTests.a */; }; 30209C98DABCE82064B4EAF5 /* libPods-SignalTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A33D3C7EB4B17BDBD47F0FCC /* libPods-SignalTests.a */; };
450873C31D9D5149006B54F2 /* 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 */; };
450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */; };
4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; }; 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 */; };
453D28B31D32B87100D523F0 /* OWSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B01D32B87100D523F0 /* OWSErrorMessage.m */; }; 453D28B31D32B87100D523F0 /* OWSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B01D32B87100D523F0 /* OWSErrorMessage.m */; };
453D28B41D32B87100D523F0 /* OWSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B21D32B87100D523F0 /* OWSInfoMessage.m */; }; 453D28B41D32B87100D523F0 /* OWSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B21D32B87100D523F0 /* OWSInfoMessage.m */; };
453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B61D32BA5F00D523F0 /* OWSDisplayedMessage.m */; }; 453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B61D32BA5F00D523F0 /* OWSDisplayedMessage.m */; };
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; }; 453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; };
453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; }; 453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; };
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */; };
45666EC91D994C0D008FE134 /* OWSGroupAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */; };
45666F561D9B2827008FE134 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */; }; 45666F561D9B2827008FE134 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */; };
45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */; }; 45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */; };
45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */; }; 45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */; };
@ -23,6 +31,8 @@
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
45843D201D2236B30013E85A /* 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 */; }; 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 */; };
458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */; }; 458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */; };
458E38341D66873D0094BD24 /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */; }; 458E38341D66873D0094BD24 /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38331D66873D0094BD24 /* OWSLinkDeviceViewController.m */; };
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; };
@ -43,6 +53,9 @@
45C681C91D305C9E0050903A /* 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 */; }; 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; };
45EB32CF1D7465C900735B2E /* OWSLinkedDevicesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 45EB32CE1D7465C900735B2E /* OWSLinkedDevicesTableViewController.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 */; };
45F2B1981D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */; };
4CE0E3771B954546007210CF /* TSAnimatedAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */; }; 4CE0E3771B954546007210CF /* TSAnimatedAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */; };
701231B518ECAA4500D456C4 /* EvpMessageDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 701231B418ECAA4500D456C4 /* EvpMessageDigest.m */; }; 701231B518ECAA4500D456C4 /* EvpMessageDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 701231B418ECAA4500D456C4 /* EvpMessageDigest.m */; };
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; }; 70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
@ -392,7 +405,6 @@
B6A3EB4B1A423B3800B2236B /* TSPhotoAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A3EB4A1A423B3800B2236B /* TSPhotoAdapter.m */; }; B6A3EB4B1A423B3800B2236B /* TSPhotoAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A3EB4A1A423B3800B2236B /* TSPhotoAdapter.m */; };
B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */; }; B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */; };
B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6B226961BE4B7D200860F4D /* ContactsUI.framework */; }; B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6B226961BE4B7D200860F4D /* ContactsUI.framework */; };
B6B2269A1BE4C59200860F4D /* APNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B226991BE4C59200860F4D /* APNavigationController.m */; };
B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B9ECFB198B31BA00C620D3 /* PushManager.m */; }; B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B9ECFB198B31BA00C620D3 /* PushManager.m */; };
B6BADBE71B88D1AC0086A80D /* LockInteractionController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */; }; B6BADBE71B88D1AC0086A80D /* LockInteractionController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */; };
B6C6AE551A305ED1006BAF8F /* redphone.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6C6AE531A305ED1006BAF8F /* redphone.cer */; }; B6C6AE551A305ED1006BAF8F /* redphone.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6C6AE531A305ED1006BAF8F /* redphone.cer */; };
@ -462,7 +474,7 @@
FC9120411A39EFB70074545C /* qr@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC91203F1A39EFB70074545C /* qr@2x.png */; }; FC9120411A39EFB70074545C /* qr@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC91203F1A39EFB70074545C /* qr@2x.png */; };
FCAC963C19FEF9280046DFC5 /* SignalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC963B19FEF9280046DFC5 /* SignalsViewController.m */; }; FCAC963C19FEF9280046DFC5 /* SignalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC963B19FEF9280046DFC5 /* SignalsViewController.m */; };
FCAC964019FEF99A0046DFC5 /* InboxTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */; }; FCAC964019FEF99A0046DFC5 /* InboxTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */; };
FCAC965119FF0A6E0046DFC5 /* MessagesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC965019FF0A6E0046DFC5 /* MessagesViewController.m */; settings = {COMPILER_FLAGS = "-Wno-receiver-is-weak"; }; }; FCAC965119FF0A6E0046DFC5 /* MessagesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAC965019FF0A6E0046DFC5 /* MessagesViewController.m */; };
FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; }; FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; };
FCB11D931A12A4AA002F93FB /* FullImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCB11D921A12A4AA002F93FB /* FullImageViewController.m */; }; FCB11D931A12A4AA002F93FB /* FullImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FCB11D921A12A4AA002F93FB /* FullImageViewController.m */; };
FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = FCC81A971A44558300DFEC7D /* UIDevice+TSHardwareVersion.m */; }; FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = FCC81A971A44558300DFEC7D /* UIDevice+TSHardwareVersion.m */; };
@ -515,8 +527,15 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
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>"; };
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>"; };
4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 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>"; }; 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>"; };
452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = OWSConversationSettingsTableViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = "<group>"; }; 453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = "<group>"; };
453D28AF1D32B87100D523F0 /* OWSErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSErrorMessage.h; sourceTree = "<group>"; }; 453D28AF1D32B87100D523F0 /* OWSErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSErrorMessage.h; sourceTree = "<group>"; };
453D28B01D32B87100D523F0 /* OWSErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSErrorMessage.m; sourceTree = "<group>"; }; 453D28B01D32B87100D523F0 /* OWSErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSErrorMessage.m; sourceTree = "<group>"; };
@ -527,6 +546,11 @@
453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessagesBubblesSizeCalculator.h; sourceTree = "<group>"; }; 453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessagesBubblesSizeCalculator.h; sourceTree = "<group>"; };
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessagesBubblesSizeCalculator.m; sourceTree = "<group>"; }; 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessagesBubblesSizeCalculator.m; sourceTree = "<group>"; };
454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; }; 454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; };
45666EC41D99483D008FE134 /* OWSAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAvatarBuilder.h; sourceTree = "<group>"; };
45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAvatarBuilder.m; sourceTree = "<group>"; };
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSGroupAvatarBuilder.h; sourceTree = "<group>"; };
45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSGroupAvatarBuilder.m; sourceTree = "<group>"; };
45666ECE1D995B94008FE134 /* OWSMessageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageData.h; sourceTree = "<group>"; };
45666F541D9B2827008FE134 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScrubbingLogFormatter.h; sourceTree = "<group>"; }; 45666F541D9B2827008FE134 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScrubbingLogFormatter.h; sourceTree = "<group>"; };
45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatter.m; sourceTree = "<group>"; }; 45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatter.m; sourceTree = "<group>"; };
45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatterTest.m; sourceTree = "<group>"; }; 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatterTest.m; sourceTree = "<group>"; };
@ -539,6 +563,8 @@
45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = "<group>"; }; 45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = "<group>"; };
45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = "<group>"; }; 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = "<group>"; };
45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = "<group>"; }; 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>"; };
458E382F1D6682450094BD24 /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; 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>"; }; 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>"; }; 458E38321D66873D0094BD24 /* OWSLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkDeviceViewController.h; sourceTree = "<group>"; };
@ -566,6 +592,10 @@
45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.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>"; }; 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>"; };
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingMessageCollectionViewCell.h; sourceTree = "<group>"; };
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingMessageCollectionViewCell.m; sourceTree = "<group>"; };
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSIncomingMessageCollectionViewCell.xib; sourceTree = "<group>"; };
45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSOutgoingMessageCollectionViewCell.xib; sourceTree = "<group>"; };
4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAnimatedAdapter.h; sourceTree = "<group>"; }; 4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAnimatedAdapter.h; sourceTree = "<group>"; };
4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAnimatedAdapter.m; sourceTree = "<group>"; }; 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAnimatedAdapter.m; sourceTree = "<group>"; };
701231B318ECAA4500D456C4 /* EvpMessageDigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EvpMessageDigest.h; sourceTree = "<group>"; }; 701231B318ECAA4500D456C4 /* EvpMessageDigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EvpMessageDigest.h; sourceTree = "<group>"; };
@ -944,8 +974,6 @@
B6B1013A196D213F007E3930 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalKeyingStorage.h; sourceTree = "<group>"; }; B6B1013A196D213F007E3930 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalKeyingStorage.h; sourceTree = "<group>"; };
B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalKeyingStorage.m; sourceTree = "<group>"; }; B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalKeyingStorage.m; sourceTree = "<group>"; };
B6B226961BE4B7D200860F4D /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; }; B6B226961BE4B7D200860F4D /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; };
B6B226981BE4C59200860F4D /* APNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APNavigationController.h; sourceTree = "<group>"; };
B6B226991BE4C59200860F4D /* APNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APNavigationController.m; sourceTree = "<group>"; };
B6B9ECFA198B31BA00C620D3 /* PushManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushManager.h; sourceTree = "<group>"; }; B6B9ECFA198B31BA00C620D3 /* PushManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushManager.h; sourceTree = "<group>"; };
B6B9ECFB198B31BA00C620D3 /* PushManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PushManager.m; sourceTree = "<group>"; }; B6B9ECFB198B31BA00C620D3 /* PushManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PushManager.m; sourceTree = "<group>"; };
B6BADBE51B88D1AC0086A80D /* LockInteractionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockInteractionController.h; sourceTree = "<group>"; }; B6BADBE51B88D1AC0086A80D /* LockInteractionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockInteractionController.h; sourceTree = "<group>"; };
@ -1047,8 +1075,8 @@
E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = "<group>"; }; E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = "<group>"; };
FC3196281A067D8F0094C78E /* MessageComposeTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageComposeTableViewController.h; sourceTree = "<group>"; }; FC3196281A067D8F0094C78E /* MessageComposeTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageComposeTableViewController.h; sourceTree = "<group>"; };
FC3196291A067D8F0094C78E /* MessageComposeTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageComposeTableViewController.m; sourceTree = "<group>"; }; FC3196291A067D8F0094C78E /* MessageComposeTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageComposeTableViewController.m; sourceTree = "<group>"; };
FC31962B1A06A2190094C78E /* FingerprintViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewController.h; sourceTree = "<group>"; }; FC31962B1A06A2190094C78E /* FingerprintViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = FingerprintViewController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
FC31962C1A06A2190094C78E /* FingerprintViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewController.m; sourceTree = "<group>"; }; FC31962C1A06A2190094C78E /* FingerprintViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FingerprintViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
FC31962E1A0814130094C78E /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = "<group>"; }; FC31962E1A0814130094C78E /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = "<group>"; };
FC31962F1A0814130094C78E /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = "<group>"; }; FC31962F1A0814130094C78E /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = "<group>"; };
FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
@ -1062,7 +1090,7 @@
FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InboxTableViewCell.h; path = "../view controllers/InboxTableViewCell.h"; sourceTree = "<group>"; }; FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InboxTableViewCell.h; path = "../view controllers/InboxTableViewCell.h"; sourceTree = "<group>"; };
FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InboxTableViewCell.m; path = "../view controllers/InboxTableViewCell.m"; sourceTree = "<group>"; }; FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InboxTableViewCell.m; path = "../view controllers/InboxTableViewCell.m"; sourceTree = "<group>"; };
FCAC964F19FF0A6E0046DFC5 /* MessagesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagesViewController.h; sourceTree = "<group>"; }; FCAC964F19FF0A6E0046DFC5 /* MessagesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagesViewController.h; sourceTree = "<group>"; };
FCAC965019FF0A6E0046DFC5 /* MessagesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessagesViewController.m; sourceTree = "<group>"; }; FCAC965019FF0A6E0046DFC5 /* MessagesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MessagesViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
FCB11D911A12A4AA002F93FB /* FullImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullImageViewController.h; sourceTree = "<group>"; }; FCB11D911A12A4AA002F93FB /* FullImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullImageViewController.h; sourceTree = "<group>"; };
FCB11D921A12A4AA002F93FB /* FullImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FullImageViewController.m; sourceTree = "<group>"; }; FCB11D921A12A4AA002F93FB /* FullImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FullImageViewController.m; sourceTree = "<group>"; };
@ -1172,6 +1200,12 @@
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */, 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */,
458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */,
458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */,
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */,
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */,
45666EC41D99483D008FE134 /* OWSAvatarBuilder.h */,
45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */,
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */,
45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1731,8 +1765,6 @@
FC3196311A08141D0094C78E /* Settings */, FC3196311A08141D0094C78E /* Settings */,
FC3196321A08142D0094C78E /* Signals */, FC3196321A08142D0094C78E /* Signals */,
FCFD25791A1543D500F4C644 /* Signup */, FCFD25791A1543D500F4C644 /* Signup */,
B6B226981BE4C59200860F4D /* APNavigationController.h */,
B6B226991BE4C59200860F4D /* APNavigationController.m */,
B6BADBE51B88D1AC0086A80D /* LockInteractionController.h */, B6BADBE51B88D1AC0086A80D /* LockInteractionController.h */,
B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */, B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */,
76EB050B18170B33006006FC /* InCallViewController.h */, 76EB050B18170B33006006FC /* InCallViewController.h */,
@ -1753,6 +1785,12 @@
45C681B91D305C080050903A /* OWSCallCollectionViewCell.h */, 45C681B91D305C080050903A /* OWSCallCollectionViewCell.h */,
45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */, 45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */,
45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */, 45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */,
450873C51D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.h */,
450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */,
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */,
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */,
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */,
45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */,
A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */, A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */,
A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */, A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */,
FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */, FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */,
@ -1762,6 +1800,9 @@
76EB053818170B33006006FC /* xibs */, 76EB053818170B33006006FC /* xibs */,
459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */, 459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */,
459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */, 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */,
450873C11D9D5149006B54F2 /* OWSExpirationTimerView.h */,
450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */,
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */,
); );
name = Views; name = Views;
path = views; path = views;
@ -1809,6 +1850,7 @@
B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */, B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */,
B6D3CBCE1C1376BE00C039DF /* TSContentAdapters.h */, B6D3CBCE1C1376BE00C039DF /* TSContentAdapters.h */,
4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */, 4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */,
45666ECE1D995B94008FE134 /* OWSMessageData.h */,
); );
name = TSMessageAdapters; name = TSMessageAdapters;
path = TSMessageAdapaters; path = TSMessageAdapaters;
@ -2311,6 +2353,8 @@
FCFD256E1A151BCB00F4C644 /* NewGroupViewController.m */, FCFD256E1A151BCB00F4C644 /* NewGroupViewController.m */,
FC4FA0241A1B9DC600DA100A /* SignalsNavigationController.h */, FC4FA0241A1B9DC600DA100A /* SignalsNavigationController.h */,
FC4FA0251A1B9DC600DA100A /* SignalsNavigationController.m */, FC4FA0251A1B9DC600DA100A /* SignalsNavigationController.m */,
452E3C8C1D935C77002A45B0 /* OWSConversationSettingsTableViewController.h */,
452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */,
); );
name = Signals; name = Signals;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2521,7 +2565,9 @@
AD83FF3F1A73426500B5C81A /* audio_pause_button_blue.png in Resources */, AD83FF3F1A73426500B5C81A /* audio_pause_button_blue.png in Resources */,
A5509ECA1A69AB8B00ABA4BC /* Storyboard.storyboard in Resources */, A5509ECA1A69AB8B00ABA4BC /* Storyboard.storyboard in Resources */,
A507A3B11A6C60E300BEED0D /* InboxTableViewCell.xib in Resources */, A507A3B11A6C60E300BEED0D /* InboxTableViewCell.xib in Resources */,
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */,
AD83FF421A73426500B5C81A /* audio_play_button.png in Resources */, AD83FF421A73426500B5C81A /* audio_play_button.png in Resources */,
45F2B1981D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib in Resources */,
45C681C41D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */, 45C681C41D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */,
B633C5C41A1D190B0059AC12 /* mute_on@2x.png in Resources */, B633C5C41A1D190B0059AC12 /* mute_on@2x.png in Resources */,
B633C5CE1A1D190B0059AC12 /* quit@2x.png in Resources */, B633C5CE1A1D190B0059AC12 /* quit@2x.png in Resources */,
@ -2720,6 +2766,7 @@
76EB058A18170B33006006FC /* Release.m in Sources */, 76EB058A18170B33006006FC /* Release.m in Sources */,
76EB061018170B33006006FC /* EventWindow.m in Sources */, 76EB061018170B33006006FC /* EventWindow.m in Sources */,
E197B62718BBF63B00F073E5 /* SoundBoard.m in Sources */, E197B62718BBF63B00F073E5 /* SoundBoard.m in Sources */,
450873C71D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */,
76EB058418170B33006006FC /* LocalizableText.m in Sources */, 76EB058418170B33006006FC /* LocalizableText.m in Sources */,
76EB057A18170B33006006FC /* OWSContactsManager.m in Sources */, 76EB057A18170B33006006FC /* OWSContactsManager.m in Sources */,
E197B61918BBEC1A00F073E5 /* RemoteIOBufferListWrapper.m in Sources */, E197B61918BBEC1A00F073E5 /* RemoteIOBufferListWrapper.m in Sources */,
@ -2732,7 +2779,9 @@
D221A09A169C9E5E00537ABF /* main.m in Sources */, D221A09A169C9E5E00537ABF /* main.m in Sources */,
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */, 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */,
76EB061618170B33006006FC /* AnonymousOccurrenceLogger.m in Sources */, 76EB061618170B33006006FC /* AnonymousOccurrenceLogger.m in Sources */,
450873C31D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */,
B6258B331C29E2E60014138E /* NotificationsManager.m in Sources */, B6258B331C29E2E60014138E /* NotificationsManager.m in Sources */,
45666EC91D994C0D008FE134 /* OWSGroupAvatarBuilder.m in Sources */,
76EB063018170B33006006FC /* Conversions.m in Sources */, 76EB063018170B33006006FC /* Conversions.m in Sources */,
76EB065618170B34006006FC /* InCallViewController.m in Sources */, 76EB065618170B34006006FC /* InCallViewController.m in Sources */,
76EB05FE18170B33006006FC /* InitiateSignal.pb.m in Sources */, 76EB05FE18170B33006006FC /* InitiateSignal.pb.m in Sources */,
@ -2754,10 +2803,12 @@
E197B61E18BBEC6D00F073E5 /* AudioRouter.m in Sources */, E197B61E18BBEC6D00F073E5 /* AudioRouter.m in Sources */,
E197B60D18BBEC1A00F073E5 /* AudioSocket.m in Sources */, E197B60D18BBEC1A00F073E5 /* AudioSocket.m in Sources */,
A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */, A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */,
45855F371D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */,
FC31962D1A06A2190094C78E /* FingerprintViewController.m in Sources */, FC31962D1A06A2190094C78E /* FingerprintViewController.m in Sources */,
76EB061418170B33006006FC /* AnonymousConditionLogger.m in Sources */, 76EB061418170B33006006FC /* AnonymousConditionLogger.m in Sources */,
76EB05C018170B33006006FC /* DhPacket.m in Sources */, 76EB05C018170B33006006FC /* DhPacket.m in Sources */,
FC3196301A0814130094C78E /* SettingsTableViewController.m in Sources */, FC3196301A0814130094C78E /* SettingsTableViewController.m in Sources */,
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */,
7038632818F70C0700D4A43F /* EvpSymetricUtil.m in Sources */, 7038632818F70C0700D4A43F /* EvpSymetricUtil.m in Sources */,
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */, 76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
B63761ED19E1FBE8005735D1 /* HttpRequestOrResponse.m in Sources */, B63761ED19E1FBE8005735D1 /* HttpRequestOrResponse.m in Sources */,
@ -2783,6 +2834,7 @@
76EB05A218170B33006006FC /* IpEndPoint.m in Sources */, 76EB05A218170B33006006FC /* IpEndPoint.m in Sources */,
E197B61A18BBEC1A00F073E5 /* SpeexCodec.m in Sources */, E197B61A18BBEC1A00F073E5 /* SpeexCodec.m in Sources */,
76EB05F018170B33006006FC /* PhoneManager.m in Sources */, 76EB05F018170B33006006FC /* PhoneManager.m in Sources */,
452E3C8E1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */,
E197B60F18BBEC1A00F073E5 /* EncodedAudioFrame.m in Sources */, E197B60F18BBEC1A00F073E5 /* EncodedAudioFrame.m in Sources */,
76EB061818170B33006006FC /* AnonymousValueLogger.m in Sources */, 76EB061818170B33006006FC /* AnonymousValueLogger.m in Sources */,
76EB05E618170B33006006FC /* CallController.m in Sources */, 76EB05E618170B33006006FC /* CallController.m in Sources */,
@ -2824,6 +2876,7 @@
FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */, FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */,
76EB054018170B33006006FC /* AppDelegate.m in Sources */, 76EB054018170B33006006FC /* AppDelegate.m in Sources */,
76EB05D018170B33006006FC /* ZrtpHandshakeSocket.m in Sources */, 76EB05D018170B33006006FC /* ZrtpHandshakeSocket.m in Sources */,
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */,
B63761EF19E1FBE8005735D1 /* HttpResponse.m in Sources */, B63761EF19E1FBE8005735D1 /* HttpResponse.m in Sources */,
E197B61518BBEC1A00F073E5 /* JitterQueue.m in Sources */, E197B61518BBEC1A00F073E5 /* JitterQueue.m in Sources */,
BFB074C919A5611000F2947C /* ObservableValue.m in Sources */, BFB074C919A5611000F2947C /* ObservableValue.m in Sources */,
@ -2839,7 +2892,6 @@
76EB059218170B33006006FC /* UnrecognizedRequestFailure.m in Sources */, 76EB059218170B33006006FC /* UnrecognizedRequestFailure.m in Sources */,
76EB05F818170B33006006FC /* CallConnectUtil_Initiator.m in Sources */, 76EB05F818170B33006006FC /* CallConnectUtil_Initiator.m in Sources */,
B62F5E101C2980B4000D370C /* NSData+ows_StripToken.m in Sources */, B62F5E101C2980B4000D370C /* NSData+ows_StripToken.m in Sources */,
B6B2269A1BE4C59200860F4D /* APNavigationController.m in Sources */,
45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */, 45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */,
B63761E319E1F487005735D1 /* AFHTTPSessionManager+SignalMethods.m in Sources */, B63761E319E1F487005735D1 /* AFHTTPSessionManager+SignalMethods.m in Sources */,
76EB05CC18170B33006006FC /* ShortAuthenticationStringGenerator.m in Sources */, 76EB05CC18170B33006006FC /* ShortAuthenticationStringGenerator.m in Sources */,
@ -2959,6 +3011,7 @@
B660F7501C29988E00687D6E /* LowLatencyConnector.m in Sources */, B660F7501C29988E00687D6E /* LowLatencyConnector.m in Sources */,
B660F7511C29988E00687D6E /* StreamPair.m in Sources */, B660F7511C29988E00687D6E /* StreamPair.m in Sources */,
B660F7521C29988E00687D6E /* Certificate.m in Sources */, B660F7521C29988E00687D6E /* Certificate.m in Sources */,
450873C41D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */,
B660F7531C29988E00687D6E /* NetworkStream.m in Sources */, B660F7531C29988E00687D6E /* NetworkStream.m in Sources */,
453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */, 453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
B660F7541C29988E00687D6E /* SecureEndPoint.m in Sources */, B660F7541C29988E00687D6E /* SecureEndPoint.m in Sources */,
@ -2983,6 +3036,7 @@
B660F7661C29988E00687D6E /* ResponderSessionDescriptor.m in Sources */, B660F7661C29988E00687D6E /* ResponderSessionDescriptor.m in Sources */,
45C681B81D305A580050903A /* OWSCall.m in Sources */, 45C681B81D305A580050903A /* OWSCall.m in Sources */,
B660F7671C29988E00687D6E /* SignalUtil.m in Sources */, B660F7671C29988E00687D6E /* SignalUtil.m in Sources */,
45855F381D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */,
B660F7681C29988E00687D6E /* CategorizingLogger.m in Sources */, B660F7681C29988E00687D6E /* CategorizingLogger.m in Sources */,
B660F7691C29988E00687D6E /* DecayingSampleEstimator.m in Sources */, B660F7691C29988E00687D6E /* DecayingSampleEstimator.m in Sources */,
B660F76A1C29988E00687D6E /* EventWindow.m in Sources */, B660F76A1C29988E00687D6E /* EventWindow.m in Sources */,
@ -3037,6 +3091,7 @@
B660F6DB1C29868000687D6E /* FunctionalUtilTest.m in Sources */, B660F6DB1C29868000687D6E /* FunctionalUtilTest.m in Sources */,
B660F6CF1C29868000687D6E /* SessionDescriptorTest.m in Sources */, B660F6CF1C29868000687D6E /* SessionDescriptorTest.m in Sources */,
B660F6C81C29868000687D6E /* PregeneratedKeyAgreementParticipantProtocol.m in Sources */, B660F6C81C29868000687D6E /* PregeneratedKeyAgreementParticipantProtocol.m in Sources */,
452E3C8F1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */,
B660F6BC1C29868000687D6E /* DnsManagerTest.m in Sources */, B660F6BC1C29868000687D6E /* DnsManagerTest.m in Sources */,
B660F6B61C29868000687D6E /* AudioRemoteIOTest.m in Sources */, B660F6B61C29868000687D6E /* AudioRemoteIOTest.m in Sources */,
B660F6D71C29868000687D6E /* Crc32Test.m in Sources */, B660F6D71C29868000687D6E /* Crc32Test.m in Sources */,
@ -3061,6 +3116,7 @@
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 */,
B660F6CA1C29868000687D6E /* LowLatencyConnectorTest.m in Sources */, B660F6CA1C29868000687D6E /* LowLatencyConnectorTest.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_hourglass_empty.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_hourglass_empty@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_hourglass_empty@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_hourglass_full.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_hourglass_full@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_hourglass_full@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_lock_outline_white.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_lock_outline_white@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_lock_outline_white@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_timer_white.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_timer_white@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_timer_white@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_empty.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_empty@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_empty@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_full.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_full@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "table_ic_hourglass_full@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "table_ic_timer.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "table_ic_timer@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "table_ic_timer@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -38,7 +38,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2.6.0.1</string> <string>2.6.0.7</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LOGS_EMAIL</key> <key>LOGS_EMAIL</key>

View File

@ -16,7 +16,8 @@
#import "TextSecureKitEnv.h" #import "TextSecureKitEnv.h"
#import "VersionMigrations.h" #import "VersionMigrations.h"
#import "OWSStaleNotificationObserver.h" #import "OWSStaleNotificationObserver.h"
#import <SignalServiceKit/OWSReadReceiptObserver.h> #import <SignalServiceKit/OWSDisappearingMessagesJob.h>
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
static NSString *const kStoryboardName = @"Storyboard"; static NSString *const kStoryboardName = @"Storyboard";
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController"; static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
@ -26,7 +27,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
@interface AppDelegate () @interface AppDelegate ()
@property (nonatomic, retain) UIWindow *screenProtectionWindow; @property (nonatomic, retain) UIWindow *screenProtectionWindow;
@property (nonatomic) OWSReadReceiptObserver *readReceiptObserver; @property (nonatomic) OWSIncomingMessageReadObserver *incomingMessageReadObserver;
@property (nonatomic) OWSStaleNotificationObserver *staleNotificationObserver; @property (nonatomic) OWSStaleNotificationObserver *staleNotificationObserver;
@end @end
@ -111,6 +112,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[[PushManager sharedManager] validateUserNotificationSettings]; [[PushManager sharedManager] validateUserNotificationSettings];
[TSPreKeyManager refreshPreKeys]; [TSPreKeyManager refreshPreKeys];
// Clean up any messages that expired since last launch.
[[[OWSDisappearingMessagesJob alloc] initWithStorageManager:[TSStorageManager sharedManager]] run];
}]; }];
[AppStoreRating setupRatingLibrary]; [AppStoreRating setupRatingLibrary];
@ -121,8 +125,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[TextSecureKitEnv sharedEnv].contactsManager = [Environment getCurrent].contactsManager; [TextSecureKitEnv sharedEnv].contactsManager = [Environment getCurrent].contactsManager;
[[TSStorageManager sharedManager] setupDatabase]; [[TSStorageManager sharedManager] setupDatabase];
[TextSecureKitEnv sharedEnv].notificationsManager = [[NotificationsManager alloc] init]; [TextSecureKitEnv sharedEnv].notificationsManager = [[NotificationsManager alloc] init];
self.readReceiptObserver = [OWSReadReceiptObserver new]; self.incomingMessageReadObserver = [[OWSIncomingMessageReadObserver alloc] initWithStorageManager:[TSStorageManager sharedManager]
[self.readReceiptObserver startObserving]; messagesManager:[TSMessagesManager sharedManager]];
[self.incomingMessageReadObserver startObserving];
self.staleNotificationObserver = [OWSStaleNotificationObserver new]; self.staleNotificationObserver = [OWSStaleNotificationObserver new];
[self.staleNotificationObserver startObserving]; [self.staleNotificationObserver startObserving];

View File

@ -0,0 +1,19 @@
// Created by Michael Kirk on 9/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
NS_ASSUME_NONNULL_BEGIN
@class TSThread;
@class OWSContactsManager;
@interface OWSAvatarBuilder : NSObject
+ (UIImage *)buildImageForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager;
- (nullable UIImage *)buildSavedImage;
- (UIImage *)buildDefaultImage;
- (UIImage *)build;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,68 @@
// Created by Michael Kirk on 9/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSAvatarBuilder.h"
#import "OWSContactAvatarBuilder.h"
#import "OWSGroupAvatarBuilder.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSAvatarBuilder
+ (UIImage *)buildImageForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager
{
OWSAvatarBuilder *avatarBuilder;
if ([thread isKindOfClass:[TSContactThread class]]) {
avatarBuilder =
[[OWSContactAvatarBuilder alloc] initWithThread:(TSContactThread *)thread contactsManager:contactsManager];
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread];
} else {
DDLogError(@"%@ called with unsupported thread: %@", self.tag, thread);
}
return [avatarBuilder build];
}
- (UIImage *)build
{
UIImage *_Nullable savedImage = [self buildSavedImage];
if (savedImage) {
return savedImage;
} else {
return [self buildDefaultImage];
}
}
- (nullable UIImage *)buildSavedImage
{
@throw [NSException
exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];
}
- (UIImage *)buildDefaultImage
{
@throw [NSException
exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,9 +1,8 @@
// Created by Dylan Bourgeois on 20/11/14. // Created by Dylan Bourgeois on 20/11/14.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved. // Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSMessageData.h"
#import "TSMessageAdapter.h" #import "TSMessageAdapter.h"
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQMessageData.h>
typedef enum : NSUInteger { typedef enum : NSUInteger {
kCallOutgoing = 1, kCallOutgoing = 1,
@ -14,7 +13,7 @@ typedef enum : NSUInteger {
kGroupUpdate = 6 kGroupUpdate = 6
} CallStatus; } CallStatus;
@interface OWSCall : NSObject <JSQMessageData, NSCoding, NSCopying> @interface OWSCall : NSObject <OWSMessageData, NSCoding, NSCopying>
/* /*
* Returns the string Id of the user who initiated the call * Returns the string Id of the user who initiated the call
@ -37,11 +36,6 @@ typedef enum : NSUInteger {
*/ */
@property (nonatomic) CallStatus status; @property (nonatomic) CallStatus status;
/*
* Returns message type for adapter
*/
@property (nonatomic) TSMessageAdapterType messageType;
/** /**
* String to be displayed * String to be displayed
*/ */

View File

@ -5,6 +5,16 @@
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h> #import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
#import <JSQMessagesViewController/UIImage+JSQMessages.h> #import <JSQMessagesViewController/UIImage+JSQMessages.h>
@interface OWSCall ()
// -- Redeclaring properties from OWSMessageData protocol to synthesize variables
@property (nonatomic) TSMessageAdapterType messageType;
@property (nonatomic, getter=isExpiringMessage) BOOL expiringMessage;
@property (nonatomic) uint64_t expiresAtSeconds;
@property (nonatomic) uint32_t expiresInSeconds;
@end
@implementation OWSCall @implementation OWSCall
#pragma mark - Initialzation #pragma mark - Initialzation
@ -37,6 +47,7 @@
_senderDisplayName = [senderDisplayName copy]; _senderDisplayName = [senderDisplayName copy];
_date = [date copy]; _date = [date copy];
_status = status; _status = status;
_expiringMessage = NO; // TODO - call notifications should expire too.
_messageType = TSCallAdapter; _messageType = TSCallAdapter;
// TODO interpret detailString from status. make sure it works for calls and // TODO interpret detailString from status. make sure it works for calls and
@ -88,6 +99,20 @@
self.date]; self.date];
} }
#pragma mark - OWSMessageEditing
- (BOOL)canPerformEditingAction:(SEL)action
{
return NO;
}
- (void)performEditingAction:(SEL)action
{
// Shouldn't get here, as only supported actions should be exposed via canPerformEditingAction
NSString *actionString = NSStringFromSelector(action);
DDLogError(@"%@ '%@' action unsupported", self.tag, actionString);
}
#pragma mark - JSQMessageData #pragma mark - JSQMessageData
- (BOOL)isMediaMessage - (BOOL)isMediaMessage
@ -141,4 +166,16 @@
return _detailString; return _detailString;
} }
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end @end

View File

@ -0,0 +1,17 @@
// Created by Michael Kirk on 9/22/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSAvatarBuilder.h"
NS_ASSUME_NONNULL_BEGIN
@class OWSContactsManager;
@class TSContactThread;
@interface OWSContactAvatarBuilder : OWSAvatarBuilder
- (instancetype)initWithThread:(TSContactThread *)thread contactsManager:(OWSContactsManager *)contactsManager;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,74 @@
// Created by Michael Kirk on 9/22/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSContactAvatarBuilder.h"
#import "OWSContactsManager.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "TSThread.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import <JSQMessagesViewController/JSQMessagesAvatarImageFactory.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactAvatarBuilder ()
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) NSString *signalId;
@property (nonatomic, readonly) NSString *contactName;
@end
@implementation OWSContactAvatarBuilder
- (instancetype)initWithThread:(TSContactThread *)thread contactsManager:(OWSContactsManager *)contactsManager
{
self = [super init];
if (!self) {
return self;
}
_signalId = thread.contactIdentifier;
_contactName = thread.name;
_contactsManager = contactsManager;
return self;
}
- (nullable UIImage *)buildSavedImage
{
return [self.contactsManager imageForPhoneIdentifier:self.signalId];
}
- (UIImage *)buildDefaultImage
{
NSMutableString *initials = [NSMutableString string];
if (self.contactName.length > 0) {
NSArray *words =
[self.contactName componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString *word in words) {
if (word.length > 0) {
NSString *firstLetter = [word substringToIndex:1];
[initials appendString:[firstLetter uppercaseString]];
}
}
}
NSRange stringRange = { 0, MIN([initials length], (NSUInteger)3) }; // Rendering max 3 letters.
initials = [[initials substringWithRange:stringRange] mutableCopy];
UIColor *backgroundColor = [UIColor backgroundColorForContact:self.signalId];
return [[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials
backgroundColor:backgroundColor
textColor:[UIColor whiteColor]
font:[UIFont ows_boldFontWithSize:36.0]
diameter:100] avatarImage];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
// Created by Michael Kirk on 9/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSAvatarBuilder.h"
NS_ASSUME_NONNULL_BEGIN
@class TSGroupThread;
@interface OWSGroupAvatarBuilder : OWSAvatarBuilder
- (instancetype)initWithThread:(TSGroupThread *)thread;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,40 @@
// Created by Michael Kirk on 9/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSGroupAvatarBuilder.h"
#import "TSGroupThread.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSGroupAvatarBuilder ()
@property (nonatomic, readonly) TSGroupThread *thread;
@end
@implementation OWSGroupAvatarBuilder
- (instancetype)initWithThread:(TSGroupThread *)thread
{
self = [super init];
if (!self) {
return self;
}
_thread = thread;
return self;
}
- (nullable UIImage *)buildSavedImage
{
return self.thread.groupModel.groupImage;
}
- (UIImage *)buildDefaultImage
{
return [UIImage imageNamed:@"empty-group-avatar"];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -3,6 +3,7 @@
#import "OWSMessagesBubblesSizeCalculator.h" #import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSDisplayedMessageCollectionViewCell.h" #import "OWSDisplayedMessageCollectionViewCell.h"
#import "TSMessageAdapter.h" #import "TSMessageAdapter.h"
#import "tgmath.h" // generic math allows fmax to handle CGFLoat correctly on 32 & 64bit.
@implementation OWSMessagesBubblesSizeCalculator @implementation OWSMessagesBubblesSizeCalculator
@ -23,11 +24,19 @@
{ {
CGSize superSize = [super messageBubbleSizeForMessageData:messageData atIndexPath:indexPath withLayout:layout]; CGSize superSize = [super messageBubbleSizeForMessageData:messageData atIndexPath:indexPath withLayout:layout];
TSMessageAdapter *message = (TSMessageAdapter *)messageData; if ([messageData isKindOfClass:[TSMessageAdapter class]]) {
if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) { TSMessageAdapter *message = (TSMessageAdapter *)messageData;
// Prevent cropping message text by accounting for message container/icon
// But also allow for multi-line error messages. if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) {
superSize.height = fmax(superSize.height, OWSDisplayedMessageCellHeight); // DDLogVerbose(@"[OWSMessagesBubblesSizeCalculator] superSize.height:%f, superSize.width:%f",
// superSize.height,
// superSize.width);
// header icon hangs ouside of the frame a bit.
CGFloat headerIconProtrusion = 30.0f; // too much padding with normal font.
// CGFloat headerIconProtrusion = 18.0f; // clips
superSize.height = superSize.height + headerIconProtrusion;
}
} }
return superSize; return superSize;

View File

@ -0,0 +1,28 @@
// Created by Michael Kirk on 9/26/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSMessageEditing.h"
#import <JSQMessagesViewController/JSQMessageData.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
TSIncomingMessageAdapter,
TSOutgoingMessageAdapter,
TSCallAdapter,
TSInfoMessageAdapter,
TSErrorMessageAdapter,
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, // Used when message direction is unknown (outgoing or incoming)
};
@protocol OWSMessageData <JSQMessageData, OWSMessageEditing>
@property (nonatomic, readonly) TSMessageAdapterType messageType;
@property (nonatomic, readonly, getter=isExpiringMessage) BOOL expiringMessage;
@property (nonatomic, readonly) uint64_t expiresAtSeconds;
@property (nonatomic, readonly) uint32_t expiresInSeconds;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,4 +1,7 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved. // Copyright © 2016 Open Whisper Systems. All rights reserved.
// Created by Michael Kirk on 3/11/16.
NS_ASSUME_NONNULL_BEGIN
@protocol OWSMessageEditing <NSObject> @protocol OWSMessageEditing <NSObject>
@ -6,3 +9,5 @@
- (void)performEditingAction:(SEL)action; - (void)performEditingAction:(SEL)action;
@end @end
NS_ASSUME_NONNULL_END

View File

@ -6,29 +6,22 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved. // Copyright (c) 2014 Open Whisper Systems. All rights reserved.
// //
#import "OWSMessageData.h"
#import "OWSMessageEditing.h" #import "OWSMessageEditing.h"
#import <JSQMessagesViewController/JSQMessageData.h>
NS_ASSUME_NONNULL_BEGIN
@class TSInteraction; @class TSInteraction;
@class TSThread; @class TSThread;
#define ME_MESSAGE_IDENTIFIER @"Me"; #define ME_MESSAGE_IDENTIFIER @"Me";
typedef NS_ENUM(NSInteger, TSMessageAdapterType) { @interface TSMessageAdapter : NSObject <OWSMessageData>
TSIncomingMessageAdapter,
TSOutgoingMessageAdapter,
TSCallAdapter,
TSInfoMessageAdapter,
TSErrorMessageAdapter,
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, // Used when message direction is unknown (outgoing or incoming)
};
@interface TSMessageAdapter : NSObject <JSQMessageData, OWSMessageEditing> + (id<OWSMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread;
+ (id<JSQMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread;
@property TSInteraction *interaction; @property TSInteraction *interaction;
@property TSMessageAdapterType messageType;
@end @end
NS_ASSUME_NONNULL_END

View File

@ -47,7 +47,12 @@
@property JSQMediaItem<OWSMessageEditing> *mediaItem; @property JSQMediaItem<OWSMessageEditing> *mediaItem;
// ---
// -- Redeclaring properties from OWSMessageData protocol to synthesize variables
@property (nonatomic) TSMessageAdapterType messageType;
@property (nonatomic, getter=isExpiringMessage) BOOL expiringMessage;
@property (nonatomic) uint64_t expiresAtSeconds;
@property (nonatomic) uint32_t expiresInSeconds;
@property (nonatomic, copy) NSDate *messageDate; @property (nonatomic, copy) NSDate *messageDate;
@property (nonatomic, retain) NSString *messageBody; @property (nonatomic, retain) NSString *messageBody;
@ -59,13 +64,34 @@
@implementation TSMessageAdapter @implementation TSMessageAdapter
+ (id<JSQMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread - (instancetype)initWithInteraction:(TSInteraction *)interaction
{ {
TSMessageAdapter *adapter = [[TSMessageAdapter alloc] init]; self = [super init];
adapter.interaction = interaction; if (!self) {
adapter.messageDate = interaction.date; return self;
}
_interaction = interaction;
_messageDate = interaction.date;
// TODO casting a string to an integer? At least need a comment here explaining why we are doing this. // TODO casting a string to an integer? At least need a comment here explaining why we are doing this.
adapter.identifier = (NSUInteger)interaction.uniqueId; // Can we just remove this? Haven't found where we're using it...
_identifier = (NSUInteger)interaction.uniqueId;
if ([interaction isKindOfClass:[TSMessage class]]) {
TSMessage *message = (TSMessage *)interaction;
_expiringMessage = message.isExpiringMessage;
_expiresAtSeconds = message.expiresAt / 1000;
_expiresInSeconds = message.expiresInSeconds;
} else {
_expiringMessage = NO;
}
return self;
}
+ (id<OWSMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread
{
TSMessageAdapter *adapter = [[TSMessageAdapter alloc] initWithInteraction:interaction];
if ([thread isKindOfClass:[TSContactThread class]]) { if ([thread isKindOfClass:[TSContactThread class]]) {
adapter.thread = (TSContactThread *)thread; adapter.thread = (TSContactThread *)thread;

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@
case UIImageOrientationDown: // EXIF = 3 case UIImageOrientationDown: // EXIF = 3
transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height); transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height);
transform = CGAffineTransformRotate(transform, M_PI); transform = CGAffineTransformRotate(transform, (CGFloat)M_PI);
break; break;
case UIImageOrientationDownMirrored: // EXIF = 4 case UIImageOrientationDownMirrored: // EXIF = 4
@ -78,25 +78,25 @@
dstSize = CGSizeMake(dstSize.height, dstSize.width); dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width); transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0); transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); transform = CGAffineTransformRotate(transform, (CGFloat)(3.0f * M_PI_2));
break; break;
case UIImageOrientationLeft: // EXIF = 6 case UIImageOrientationLeft: // EXIF = 6
dstSize = CGSizeMake(dstSize.height, dstSize.width); dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(0.0, srcSize.width); transform = CGAffineTransformMakeTranslation(0.0, srcSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); transform = CGAffineTransformRotate(transform, (CGFloat)(3.0 * M_PI_2));
break; break;
case UIImageOrientationRightMirrored: // EXIF = 7 case UIImageOrientationRightMirrored: // EXIF = 7
dstSize = CGSizeMake(dstSize.height, dstSize.width); dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeScale(-1.0, 1.0); transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI_2); transform = CGAffineTransformRotate(transform, (CGFloat)M_PI_2);
break; break;
case UIImageOrientationRight: // EXIF = 8 case UIImageOrientationRight: // EXIF = 8
dstSize = CGSizeMake(dstSize.height, dstSize.width); dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0); transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI_2); transform = CGAffineTransformRotate(transform, (CGFloat)M_PI_2);
break; break;
default: default:
@ -166,10 +166,10 @@
if (wRatio < hRatio) { if (wRatio < hRatio) {
// NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio); // NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio);
dstSize = CGSizeMake(boundingSize.width, floor(srcSize.height * wRatio)); dstSize = CGSizeMake(boundingSize.width, (CGFloat)floor(srcSize.height * wRatio));
} else { } else {
// NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio); // NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio);
dstSize = CGSizeMake(floor(srcSize.width * hRatio), boundingSize.height); dstSize = CGSizeMake((CGFloat)floor(srcSize.width * hRatio), boundingSize.height);
} }
} }

View File

@ -1,25 +0,0 @@
//
// APNavigationController.h
// DropDownToolBar
//
// Created by Ankur Patel on 2/24/14.
// Copyright (c) 2014 Encore Dev Labs LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface APNavigationController : UINavigationController
@property (nonatomic, strong)
UIToolbar *dropDownToolbar; // Reference to dynamically change items based on which bar button item is clicked
@property (nonatomic, strong) NSString *activeNavigationBarTitle; // Navigation bar title when the toolbar is shown
@property (nonatomic, strong) NSString *activeBarButtonTitle; // UIBarButton title when toolbar is shown
@property (nonatomic, assign) BOOL isDropDownVisible;
- (void)setActiveBarButtonTitle:(NSString *)title;
- (void)setActiveNavigationBarTitle:(NSString *)title;
- (void)toggleDropDown:(id)sender;
- (void)hideDropDown:(id)sender;
- (void)showDropDown:(id)sender;
@end

View File

@ -1,99 +0,0 @@
//
// APNavigationController.m
// DropDownToolBar
//
// Created by Ankur Patel on 2/24/14.
// Copyright (c) 2014 Encore Dev Labs LLC. All rights reserved.
//
#import "APNavigationController.h"
@interface APNavigationController ()
@property (nonatomic, copy) NSString *originalNavigationBarTitle;
@property (nonatomic, copy) NSString *originalBarButtonTitle;
@end
@implementation APNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.dropDownToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 64)];
self.dropDownToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.dropDownToolbar.tintColor = self.navigationBar.tintColor;
[self.navigationBar.superview insertSubview:self.dropDownToolbar belowSubview:self.navigationBar];
self.originalNavigationBarTitle = self.navigationBar.topItem.title;
}
- (void)toggleDropDown:(id)sender {
if (self.isDropDownVisible) {
[self hideDropDown:sender];
} else {
[self showDropDown:sender];
}
}
- (void)hideDropDown:(id)sender {
if (self.isDropDownVisible) {
__weak APNavigationController *weakSelf = self;
CGRect frame = self.dropDownToolbar.frame;
frame.origin.y = CGRectGetMaxY(self.navigationBar.frame);
self.dropDownToolbar.frame = frame;
[UIView animateWithDuration:0.25
animations:^{
CGRect finalframe = self.dropDownToolbar.frame;
finalframe.origin.y = 0.;
weakSelf.dropDownToolbar.frame = finalframe;
}
completion:^(BOOL finished) {
weakSelf.isDropDownVisible = !weakSelf.isDropDownVisible;
weakSelf.dropDownToolbar.hidden = YES;
}];
if (self.activeNavigationBarTitle) {
self.navigationBar.topItem.title = self.originalNavigationBarTitle;
}
if (sender && [sender isKindOfClass:[UIBarButtonItem class]]) {
[(UIBarButtonItem *)sender setTitle:self.originalBarButtonTitle];
}
}
}
- (void)showDropDown:(id)sender {
if (!self.isDropDownVisible) {
__weak APNavigationController *weakSelf = self;
CGRect frame = self.dropDownToolbar.frame;
frame.origin.y = 0.f;
self.dropDownToolbar.hidden = NO;
self.dropDownToolbar.frame = frame;
[UIView animateWithDuration:0.25
animations:^{
CGRect finalframe = self.dropDownToolbar.frame;
finalframe.origin.y = CGRectGetMaxY(self.navigationBar.frame);
weakSelf.dropDownToolbar.frame = finalframe;
}
completion:^(BOOL finished) {
weakSelf.isDropDownVisible = !weakSelf.isDropDownVisible;
}];
if (self.activeNavigationBarTitle) {
self.navigationBar.topItem.title = self.activeNavigationBarTitle;
}
if (sender && [sender isKindOfClass:[UIBarButtonItem class]]) {
self.originalBarButtonTitle = [(UIBarButtonItem *)sender title];
if (self.activeBarButtonTitle) {
[(UIBarButtonItem *)sender setTitle:self.activeBarButtonTitle];
}
}
}
}
@end

View File

@ -12,12 +12,16 @@ NS_ASSUME_NONNULL_BEGIN
@class TSThread; @class TSThread;
@class OWSFingerprint; @class OWSFingerprint;
@class OWSConversationSettingsTableViewController;
@interface FingerprintViewController : UIViewController <OWSQRScannerDelegate> @interface FingerprintViewController : UIViewController <OWSQRScannerDelegate>
@property (nullable) OWSConversationSettingsTableViewController *dismissDelegate;
- (void)configureWithThread:(TSThread *)thread - (void)configureWithThread:(TSThread *)thread
fingerprint:(OWSFingerprint *)fingerprint fingerprint:(OWSFingerprint *)fingerprint
contactName:(NSString *)contactName; contactName:(NSString *)contactName;
- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithData:(NSData *)data; - (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithData:(NSData *)data;
@end @end

View File

@ -8,6 +8,7 @@
#import "FingerprintViewController.h" #import "FingerprintViewController.h"
#import "DJWActionSheet+OWS.h" #import "DJWActionSheet+OWS.h"
#import "OWSConversationSettingsTableViewController.h"
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h> #import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
#import <SignalServiceKit/OWSFingerprint.h> #import <SignalServiceKit/OWSFingerprint.h>
#import <SignalServiceKit/TSInfoMessage.h> #import <SignalServiceKit/TSInfoMessage.h>
@ -27,7 +28,10 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) NSString *contactName; @property (strong, nonatomic) NSString *contactName;
@property (strong, nonatomic) OWSQRCodeScanningViewController *qrScanningController; @property (strong, nonatomic) OWSQRCodeScanningViewController *qrScanningController;
@property (strong, nonatomic) IBOutlet UINavigationBar *modalNavigationBar;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *dismissModalButton;
@property (strong, nonatomic) IBOutlet UIView *qrScanningView; @property (strong, nonatomic) IBOutlet UIView *qrScanningView;
@property (strong, nonatomic) IBOutlet UILabel *scanningInstructions;
@property (strong, nonatomic) IBOutlet UIView *scanningContainer; @property (strong, nonatomic) IBOutlet UIView *scanningContainer;
@property (strong, nonatomic) IBOutlet UIView *instructionsContainer; @property (strong, nonatomic) IBOutlet UIView *instructionsContainer;
@property (strong, nonatomic) IBOutlet UIView *qrContainer; @property (strong, nonatomic) IBOutlet UIView *qrContainer;
@ -35,9 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) IBOutlet UIImageView *privacyVerificationQRCode; @property (strong, nonatomic) IBOutlet UIImageView *privacyVerificationQRCode;
@property (strong, nonatomic) IBOutlet UILabel *privacyVerificationFingerprint; @property (strong, nonatomic) IBOutlet UILabel *privacyVerificationFingerprint;
@property (strong, nonatomic) IBOutlet UILabel *instructionsLabel; @property (strong, nonatomic) IBOutlet UILabel *instructionsLabel;
@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
@property (strong, nonatomic) IBOutlet UIButton *scanButton; @property (strong, nonatomic) IBOutlet UIButton *scanButton;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *qrCodeCenterConstraint;
@end @end
@ -55,8 +57,16 @@ NS_ASSUME_NONNULL_BEGIN
- (void)viewDidLoad - (void)viewDidLoad
{ {
[super viewDidLoad]; [super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.dismissModalButton;
[self.modalNavigationBar pushNavigationItem:self.navigationItem animated:NO];
// HACK for transparent navigation bar.
[self.modalNavigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.modalNavigationBar.shadowImage = [UIImage new];
self.modalNavigationBar.translucent = YES;
self.storageManager = [TSStorageManager sharedManager]; self.storageManager = [TSStorageManager sharedManager];
self.qrScanningView.hidden = YES;
// HACK to get full width preview layer // HACK to get full width preview layer
CGRect oldFrame = self.qrScanningView.frame; CGRect oldFrame = self.qrScanningView.frame;
@ -67,7 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
self.qrScanningView.frame = newFrame; self.qrScanningView.frame = newFrame;
// END HACK to get full width preview layer // END HACK to get full width preview layer
self.titleLabel.text = NSLocalizedString(@"PRIVACY_VERIFICATION_TITLE", @"Navbar title"); self.title = NSLocalizedString(@"PRIVACY_VERIFICATION_TITLE", @"Navbar title");
NSString *instructionsFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_INSTRUCTIONS", NSString *instructionsFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_INSTRUCTIONS",
@"Paragraph(s) shown alongside keying material when verifying privacy with {{contact name}}"); @"Paragraph(s) shown alongside keying material when verifying privacy with {{contact name}}");
self.instructionsLabel.text = [NSString stringWithFormat:instructionsFormat, self.contactName]; self.instructionsLabel.text = [NSString stringWithFormat:instructionsFormat, self.contactName];
@ -97,6 +107,14 @@ NS_ASSUME_NONNULL_BEGIN
self.privacyVerificationQRCodeFrame.layer.cornerRadius = self.privacyVerificationQRCodeFrame.frame.size.height / 2; self.privacyVerificationQRCodeFrame.layer.cornerRadius = self.privacyVerificationQRCodeFrame.frame.size.height / 2;
} }
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
if (self.dismissDelegate) {
[self.dismissDelegate presentedModalWasDismissed];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender
{ {
if ([segue.identifier isEqualToString:@"embedIdentityQRScanner"]) { if ([segue.identifier isEqualToString:@"embedIdentityQRScanner"]) {
@ -150,23 +168,14 @@ NS_ASSUME_NONNULL_BEGIN
{ {
DDLogInfo(@"%@ Showing Scanner", self.tag); DDLogInfo(@"%@ Showing Scanner", self.tag);
self.qrScanningView.hidden = NO; self.qrScanningView.hidden = NO;
self.scanningInstructions.hidden = NO;
// Recommended before animating a constraint.
[self.view layoutIfNeeded];
// Shift QRCode up within it's own frame, while shifting it's whole
// frame down.
self.qrCodeCenterConstraint.constant = 0.0f;
[UIView animateWithDuration:0.4 [UIView animateWithDuration:0.4
delay:0.0 delay:0.0
options:UIViewAnimationOptionCurveEaseInOut options:UIViewAnimationOptionCurveEaseInOut
animations:^{ animations:^{
self.scanningContainer.frame = self.qrContainer.frame; self.scanningContainer.frame = self.qrContainer.frame;
self.qrContainer.frame = self.instructionsContainer.frame; self.qrContainer.frame = self.instructionsContainer.frame;
self.instructionsContainer.alpha = 0.0f; self.instructionsContainer.alpha = 0.0f;
// animate constraint smoothly
[self.view layoutIfNeeded];
} }
completion:nil]; completion:nil];
@ -254,6 +263,8 @@ NS_ASSUME_NONNULL_BEGIN
[super dismissViewControllerAnimated:flag completion:completion]; [super dismissViewControllerAnimated:flag completion:completion];
} }
#pragma mark - Logging
+ (NSString *)tag + (NSString *)tag
{ {
return [NSString stringWithFormat:@"[%@]", self.class]; return [NSString stringWithFormat:@"[%@]", self.class];

View File

@ -4,6 +4,10 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "TSThread.h" #import "TSThread.h"
NS_ASSUME_NONNULL_BEGIN
@class OWSContactsManager;
typedef enum : NSUInteger { kArchiveState = 0, kInboxState = 1 } CellState; typedef enum : NSUInteger { kArchiveState = 0, kInboxState = 1 } CellState;
@interface InboxTableViewCell : UITableViewCell <UIScrollViewDelegate> @interface InboxTableViewCell : UITableViewCell <UIScrollViewDelegate>
@ -17,7 +21,10 @@ typedef enum : NSUInteger { kArchiveState = 0, kInboxState = 1 } CellState;
@property (nonatomic, retain) NSString *threadId; @property (nonatomic, retain) NSString *threadId;
+ (instancetype)inboxTableViewCell; + (instancetype)inboxTableViewCell;
- (void)configureWithThread:(TSThread *)thread;
- (void)configureWithThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager;
- (void)animateDisappear; - (void)animateDisappear;
@end @end
NS_ASSUME_NONNULL_END

View File

@ -1,15 +1,18 @@
// Created by Dylan Bourgeois on 27/10/14. // Created by Dylan Bourgeois on 27/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved. // Copyright (c) 2014 Open Whisper Systems. All rights reserved.
#import <JSQMessagesViewController/JSQMessagesAvatarImageFactory.h>
#import <JSQMessagesViewController/UIImage+JSQMessages.h>
#import "Environment.h"
#import "InboxTableViewCell.h" #import "InboxTableViewCell.h"
#import "Environment.h"
#import "OWSAvatarBuilder.h"
#import "PreferencesUtil.h" #import "PreferencesUtil.h"
#import "TSContactThread.h" #import "TSContactThread.h"
#import "TSGroupThread.h" #import "TSGroupThread.h"
#import "TSMessagesManager.h" #import "TSMessagesManager.h"
#import "Util.h" #import "Util.h"
#import <JSQMessagesViewController/JSQMessagesAvatarImageFactory.h>
#import <JSQMessagesViewController/UIImage+JSQMessages.h>
NS_ASSUME_NONNULL_BEGIN
#define ARCHIVE_IMAGE_VIEW_WIDTH 22.0f #define ARCHIVE_IMAGE_VIEW_WIDTH 22.0f
#define DELETE_IMAGE_VIEW_WIDTH 19.0f #define DELETE_IMAGE_VIEW_WIDTH 19.0f
@ -39,86 +42,45 @@
self.selectionStyle = UITableViewCellSelectionStyleDefault; self.selectionStyle = UITableViewCellSelectionStyleDefault;
} }
- (NSString *)reuseIdentifier { - (nullable NSString *)reuseIdentifier
{
return NSStringFromClass(self.class); return NSStringFromClass(self.class);
} }
- (void)configureWithThread:(TSThread *)thread { - (void)configureWithThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager
{
if (!_threadId || ![_threadId isEqualToString:thread.uniqueId]) { if (!_threadId || ![_threadId isEqualToString:thread.uniqueId]) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.hidden = YES; self.hidden = YES;
}); });
} }
NSString *name = thread.name; NSString *name = thread.name;
_threadId = thread.uniqueId; if (name.length == 0 && [thread isKindOfClass:[TSGroupThread class]]) {
name = NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @"");
}
UIImage *avatar = [OWSAvatarBuilder buildImageForThread:thread contactsManager:contactsManager];
self.threadId = thread.uniqueId;
NSString *snippetLabel = thread.lastMessageLabel; NSString *snippetLabel = thread.lastMessageLabel;
NSAttributedString *attributedDate = [self dateAttributedString:thread.lastMessageDate]; NSAttributedString *attributedDate = [self dateAttributedString:thread.lastMessageDate];
NSUInteger unreadCount = [[TSMessagesManager sharedManager] unreadMessagesInThread:thread]; NSUInteger unreadCount = [[TSMessagesManager sharedManager] unreadMessagesInThread:thread];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
_nameLabel.text = name; self.nameLabel.text = name;
_snippetLabel.text = snippetLabel; self.snippetLabel.text = snippetLabel;
_timeLabel.attributedText = attributedDate; self.timeLabel.attributedText = attributedDate;
self.contactPictureView.image = avatar;
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
if ([thread isKindOfClass:[TSGroupThread class]]) { self.separatorInset = UIEdgeInsetsMake(0, _contactPictureView.frame.size.width * 1.5f, 0, 0);
_contactPictureView.contentMode = UIViewContentModeScaleAspectFill;
_contactPictureView.image = ((TSGroupThread *)thread).groupModel.groupImage != nil
? ((TSGroupThread *)thread).groupModel.groupImage
: [UIImage imageNamed:@"empty-group-avatar"];
if ([_nameLabel.text length] == 0) {
_nameLabel.text = NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @"");
}
if (_contactPictureView.image != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
});
}
} else {
NSMutableString *initials = [NSMutableString string];
if ([name length] > 0) { if (thread.hasUnreadMessages) {
NSArray *words = [name componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; [self updateCellForUnreadMessage];
for (NSString *word in words) { } else {
if ([word length] > 0) { [self updateCellForReadMessage];
NSString *firstLetter = [word substringToIndex:1]; }
[initials appendString:[firstLetter uppercaseString]]; [self setUnreadMsgCount:unreadCount];
} self.hidden = NO;
}
}
NSRange stringRange = {0, MIN([initials length], (NSUInteger)3)}; // Rendering max 3 letters.
initials = [[initials substringWithRange:stringRange] mutableCopy];
UIColor *backgroundColor =
thread.isGroupThread ? [UIColor whiteColor]
: [UIColor backgroundColorForContact:((TSContactThread *)thread).contactIdentifier];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image =
[[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials
backgroundColor:backgroundColor
textColor:[UIColor whiteColor]
font:[UIFont ows_boldFontWithSize:36.0]
diameter:100] avatarImage];
dispatch_async(dispatch_get_main_queue(), ^{
_contactPictureView.image = thread.image != nil ? thread.image : image;
if (thread.image != nil) {
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
}
});
});
}
self.separatorInset = UIEdgeInsetsMake(0, _contactPictureView.frame.size.width * 1.5f, 0, 0);
if (thread.hasUnreadMessages) {
[self updateCellForUnreadMessage];
} else {
[self updateCellForReadMessage];
}
[self setUnreadMsgCount:unreadCount];
self.hidden = NO;
}); });
} }
@ -202,11 +164,11 @@
[_unreadLabel sizeToFit]; [_unreadLabel sizeToFit];
CGPoint offset = CGPointMake(0.0f, 5.0f); CGPoint offset = CGPointMake(0.0f, 5.0f);
_unreadLabel.frame = _unreadLabel.frame
CGRectMake(offset.x + floor((2.0f * (25 - _unreadLabel.frame.size.width) / 2.0f) / 2.0f), = CGRectMake(offset.x + (CGFloat)floor((2.0f * (25.0f - _unreadLabel.frame.size.width) / 2.0f) / 2.0f),
offset.y, offset.y,
_unreadLabel.frame.size.width, _unreadLabel.frame.size.width,
_unreadLabel.frame.size.height); _unreadLabel.frame.size.height);
_messageCounter.hidden = NO; _messageCounter.hidden = NO;
} else { } else {
_messageCounter.hidden = YES; _messageCounter.hidden = YES;
@ -225,3 +187,5 @@
@end @end
NS_ASSUME_NONNULL_END

View File

@ -222,9 +222,9 @@
[self.sendTextButton setBackgroundColor:[UIColor ows_materialBlueColor]]; [self.sendTextButton setBackgroundColor:[UIColor ows_materialBlueColor]];
[self.sendTextButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [self.sendTextButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.sendTextButton.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.sendTextButton.frame = CGRectMake(self.searchController.searchBar.frame.origin.x,
self.searchController.searchBar.frame.origin.y + 44.0, self.searchController.searchBar.frame.origin.y + 44.0f,
self.searchController.searchBar.frame.size.width, self.searchController.searchBar.frame.size.width,
44.0); 44.0);
[self.view addSubview:self.sendTextButton]; [self.view addSubview:self.sendTextButton];
self.sendTextButton.hidden = YES; self.sendTextButton.hidden = YES;

View File

@ -8,11 +8,12 @@
#import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h> #import <MediaPlayer/MediaPlayer.h>
#import "APNavigationController.h"
#import <JSQMessagesViewController/JSQMessagesViewController.h> #import <JSQMessagesViewController/JSQMessagesViewController.h>
#import "TSGroupModel.h" #import "TSGroupModel.h"
@class TSThread; @class TSThread;
extern NSString *const OWSMessagesViewControllerDidAppearNotification;
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate, @interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate,
UINavigationControllerDelegate, UINavigationControllerDelegate,
UITextViewDelegate, UITextViewDelegate,
@ -22,7 +23,6 @@
@property (nonatomic, readonly) TSThread *thread; @property (nonatomic, readonly) TSThread *thread;
@property (nonatomic, retain) APNavigationController *navController;
@property (nonatomic, strong) MPMoviePlayerController *videoPlayer; @property (nonatomic, strong) MPMoviePlayerController *videoPlayer;
@property (nonatomic, strong) AVAudioPlayer *audioPlayer; @property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@property (nonatomic, strong) AVAudioRecorder *audioRecorder; @property (nonatomic, strong) AVAudioRecorder *audioRecorder;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
// Created by Michael Kirk on 9/21/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class TSThread;
@interface OWSConversationSettingsTableViewController : UITableViewController
- (void)configureWithThread:(TSThread *)thread;
- (void)presentedModalWasDismissed;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,459 @@
// Created by Michael Kirk on 9/21/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSConversationSettingsTableViewController.h"
#import "Environment.h"
#import "FingerprintViewController.h"
#import "NewGroupViewController.h"
#import "OWSAvatarBuilder.h"
#import "OWSContactsManager.h"
#import "PhoneNumber.h"
#import "ShowGroupMembersViewController.h"
#import "UIUtil.h"
#import <25519/Curve25519.h>
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
#import <SignalServiceKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSFingerprint.h>
#import <SignalServiceKit/OWSFingerprintBuilder.h>
#import <SignalServiceKit/OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob.h>
#import <SignalServiceKit/TSGroupThread.h>
#import <SignalServiceKit/TSMessagesManager+sendMessages.h>
#import <SignalServiceKit/TSStorageManager.h>
#import <SignalServiceKit/TSThread.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, OWSConversationSettingsTableViewControllerSection) {
OWSConversationSettingsTableViewControllerSectionContact,
OWSConversationSettingsTableViewControllerSectionGroup
};
typedef NS_ENUM(NSUInteger, OWSConversationSettingsTableViewControllerContactCellIndex) {
OWSConversationSettingsTableViewControllerCellIndexShowFingerprint,
OWSConversationSettingsTableViewControllerCellIndexToggleDisappearingMessages,
OWSConversationSettingsTableViewControllerCellIndexSetDisappearingMessagesDuration
};
typedef NS_ENUM(NSUInteger, OWSConversationSettingsTableViewControllerGroupCellIndex) {
OWSConversationSettingsTableViewControllerCellIndexUpdateGroup,
OWSConversationSettingsTableViewControllerCellIndexLeaveGroup,
OWSConversationSettingsTableViewControllerCellIndexSeeGroupMembers
};
static NSString *const OWSConversationSettingsTableViewControllerSegueUpdateGroup =
@"OWSConversationSettingsTableViewControllerSegueUpdateGroup";
static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupMembers =
@"OWSConversationSettingsTableViewControllerSegueShowGroupMembers";
@interface OWSConversationSettingsTableViewController ()
@property (strong, nonatomic) IBOutlet UITableViewCell *verifyPrivacyCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *toggleDisappearingMessagesCell;
@property (strong, nonatomic) IBOutlet UISwitch *disappearingMessagesSwitch;
@property (strong, nonatomic) IBOutlet UITableViewCell *disappearingMessagesDurationCell;
@property (strong, nonatomic) IBOutlet UILabel *disappearingMessagesDurationLabel;
@property (strong, nonatomic) IBOutlet UISlider *disappearingMessagesDurationSlider;
@property (strong, nonatomic) IBOutlet UITableViewCell *updateGroupCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *leaveGroupCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *listGroupMembersCell;
@property (strong, nonatomic) IBOutlet UIImageView *avatar;
@property (strong, nonatomic) IBOutlet UILabel *nameLabel;
@property (strong, nonatomic) IBOutlet UILabel *signalIdLabel;
@property (nonatomic) TSThread *thread;
@property (nonatomic) NSString *contactName;
@property (nonatomic) NSString *signalId;
@property (nonatomic) UIImage *avatarImage;
@property (nonatomic) BOOL isGroupThread;
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
@property (nonatomic) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
@property (nonatomic, readonly) TSStorageManager *storageManager;
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@end
@implementation OWSConversationSettingsTableViewController
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_storageManager = [TSStorageManager sharedManager];
_contactsManager = [[Environment getCurrent] contactsManager];
_messagesManager = [TSMessagesManager sharedManager];
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
_storageManager = [TSStorageManager sharedManager];
_contactsManager = [[Environment getCurrent] contactsManager];
_messagesManager = [TSMessagesManager sharedManager];
return self;
}
- (void)configureWithThread:(TSThread *)thread
{
self.thread = thread;
self.signalId = thread.contactIdentifier;
self.contactName = thread.name;
if ([thread isKindOfClass:[TSGroupThread class]]) {
self.isGroupThread = YES;
if (self.contactName.length == 0) {
self.contactName = NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @"");
}
} else {
self.isGroupThread = NO;
}
}
#pragma mark - View Lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.nameLabel.text = self.contactName;
if (self.signalId) {
self.signalIdLabel.text =
[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:self.signalId];
} else {
// Don't print anything for groups.
self.signalIdLabel.text = nil;
}
self.avatar.image = [OWSAvatarBuilder buildImageForThread:self.thread contactsManager:self.contactsManager];
// Translations
self.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen");
self.verifyPrivacyCell.textLabel.text
= NSLocalizedString(@"VERIFY_PRIVACY", @"table cell label in conversation settings");
self.toggleDisappearingMessagesCell.textLabel.text
= NSLocalizedString(@"DISAPPEARING_MESSAGES", @"table cell label in conversation settings");
self.updateGroupCell.textLabel.text
= NSLocalizedString(@"EDIT_GROUP_ACTION", @"table cell label in conversation settings");
self.leaveGroupCell.textLabel.text
= NSLocalizedString(@"LEAVE_GROUP_ACTION", @"table cell label in conversation settings");
self.listGroupMembersCell.textLabel.text
= NSLocalizedString(@"LIST_GROUP_MEMBERS_ACTION", @"table cell label in conversation settings");
self.toggleDisappearingMessagesCell.selectionStyle = UITableViewCellSelectionStyleNone;
self.disappearingMessagesDurationCell.selectionStyle = UITableViewCellSelectionStyleNone;
self.disappearingMessagesDurations = [OWSDisappearingMessagesConfiguration validDurationsSeconds];
self.disappearingMessagesDurationSlider.maximumValue = (float)(self.disappearingMessagesDurations.count - 1);
self.disappearingMessagesDurationSlider.minimumValue = 0;
self.disappearingMessagesDurationSlider.continuous = YES; // NO fires change event only once you let go
self.disappearingMessagesConfiguration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:self.thread.uniqueId];
if (!self.disappearingMessagesConfiguration) {
self.disappearingMessagesConfiguration =
[[OWSDisappearingMessagesConfiguration alloc] initDefaultWithThreadId:self.thread.uniqueId];
}
self.disappearingMessagesDurationSlider.value = self.disappearingMessagesConfiguration.durationIndex;
[self toggleDisappearingMessages:self.disappearingMessagesConfiguration.isEnabled];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// HACK to unselect rows when swiping back
// http://stackoverflow.com/questions/19379510/uitableviewcell-doesnt-get-deselected-when-swiping-back-quickly
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (self.disappearingMessagesConfiguration.isNewRecord && !self.disappearingMessagesConfiguration.isEnabled) {
// don't save defaults, else we'll unintentionally save the configuration and notify the contact.
return;
}
if (self.disappearingMessagesConfiguration.dictionaryValueDidChange) {
[self.disappearingMessagesConfiguration save];
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:self.thread
configuration:self.disappearingMessagesConfiguration];
[infoMessage save];
[OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob
runWithConfiguration:self.disappearingMessagesConfiguration
thread:self.thread
messagesManager:self.messagesManager];
}
}
- (void)viewDidLayoutSubviews
{
// Round avatar corners.
self.avatar.layer.borderColor = UIColor.clearColor.CGColor;
self.avatar.layer.masksToBounds = YES;
self.avatar.layer.cornerRadius = self.avatar.frame.size.height / 2.0f;
}
#pragma mark - UITableViewDelegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger baseCount = [super tableView:tableView numberOfRowsInSection:section];
if (section == OWSConversationSettingsTableViewControllerSectionGroup) {
if (self.isGroupThread) {
return baseCount;
} else {
return 0;
}
}
if (section == OWSConversationSettingsTableViewControllerSectionContact) {
if (self.isGroupThread) {
// No fingerprint for group thread.
baseCount -= 1;
}
if (!self.disappearingMessagesSwitch.isOn) {
// hide duration slider when disappearing messages is off.
baseCount -= 1;
}
}
return baseCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
if (self.isGroupThread && indexPath.section == OWSConversationSettingsTableViewControllerSectionContact) {
// Since fingerprint cell is hidden for group threads we offset our index path
NSIndexPath *offsetIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
return [super tableView:tableView cellForRowAtIndexPath:offsetIndexPath];
}
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell == self.disappearingMessagesDurationCell) {
NSIndexPath *originalDurationSliderIndexPath = [NSIndexPath
indexPathForRow:OWSConversationSettingsTableViewControllerCellIndexSetDisappearingMessagesDuration
inSection:OWSConversationSettingsTableViewControllerSectionContact];
return [super tableView:tableView heightForRowAtIndexPath:originalDurationSliderIndexPath];
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
// Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection.
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// Don't highlight rows that have no selection style.
if (cell.selectionStyle == UITableViewCellSelectionStyleNone) {
return nil;
}
return indexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DDLogDebug(@"%@ tapped indexPath:%@", self.tag, indexPath);
if (indexPath.section == OWSConversationSettingsTableViewControllerSectionGroup
&& indexPath.row == OWSConversationSettingsTableViewControllerCellIndexLeaveGroup) {
[self didTapLeaveGroup];
}
}
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == OWSConversationSettingsTableViewControllerSectionGroup) {
if (self.isGroupThread) {
return NSLocalizedString(@"GROUP_MANAGEMENT_SECTION", @"Conversation settings table section title");
} else {
return nil;
}
} else {
return [super tableView:tableView titleForHeaderInSection:section];
}
}
#pragma mark - Actions
- (void)didTapLeaveGroup
{
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"CONFIRM_LEAVE_GROUP_TITLE", @"Alert title")
message:NSLocalizedString(@"CONFIRM_LEAVE_GROUP_DESCRIPTION", @"Alert body")
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *leaveAction = [UIAlertAction
actionWithTitle:NSLocalizedString(@"LEAVE_BUTTON_TITLE", @"Confirmation button within contextual alert")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[self leaveGroup];
}];
[alertController addAction:leaveAction];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)leaveGroup
{
TSGroupThread *gThread = (TSGroupThread *)self.thread;
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:gThread
messageBody:@""];
message.groupMetaMessage = TSGroupMessageQuit;
[self.messagesManager sendMessage:message
inThread:gThread
success:^{
DDLogInfo(@"%@ Successfully left group.", self.tag);
}
failure:^{
DDLogWarn(@"%@ Failed to leave group", self.tag);
}];
NSMutableArray *newGroupMemberIds = [NSMutableArray arrayWithArray:gThread.groupModel.groupMemberIds];
[newGroupMemberIds removeObject:[self.storageManager localNumber]];
gThread.groupModel.groupMemberIds = newGroupMemberIds;
[gThread save];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)presentedModalWasDismissed
{
// Else row stays selected after dismissing modal.
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
- (IBAction)disappearingMessagesSwitchValueDidChange:(id)sender
{
if (![sender isKindOfClass:[UISwitch class]]) {
DDLogError(@"%@ Unexpected sender for disappearing messages switch: %@", self.tag, sender);
}
UISwitch *disappearingMessagesSwitch = (UISwitch *)sender;
[self toggleDisappearingMessages:disappearingMessagesSwitch.isOn];
}
- (void)toggleDisappearingMessages:(BOOL)flag
{
self.disappearingMessagesConfiguration.enabled = flag;
// When this message is called as a result of the switch being flipped, this will be a no-op
// but it allows us to resuse the method to set the switch programmatically in view setup.
self.disappearingMessagesSwitch.on = flag;
[self durationSliderDidChange:self.disappearingMessagesDurationSlider];
// Animate show/hide of duration settings.
if (flag) {
[self.tableView insertRowsAtIndexPaths:@[ self.indexPathForDurationSlider ]
withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
[self.tableView deleteRowsAtIndexPaths:@[ self.indexPathForDurationSlider ]
withRowAnimation:UITableViewRowAnimationTop];
}
}
- (NSIndexPath *)indexPathForDurationSlider
{
if (self.isGroupThread) {
return [NSIndexPath
indexPathForRow:OWSConversationSettingsTableViewControllerCellIndexSetDisappearingMessagesDuration - 1
inSection:OWSConversationSettingsTableViewControllerSectionContact];
} else {
return [NSIndexPath
indexPathForRow:OWSConversationSettingsTableViewControllerCellIndexSetDisappearingMessagesDuration
inSection:OWSConversationSettingsTableViewControllerSectionContact];
}
}
- (IBAction)durationSliderDidChange:(UISlider *)slider
{
// snap the slider to a valid value
NSUInteger index = (NSUInteger)(slider.value + 0.5);
[slider setValue:index animated:YES];
NSNumber *numberOfSeconds = self.disappearingMessagesDurations[index];
self.disappearingMessagesConfiguration.durationSeconds = [numberOfSeconds unsignedIntValue];
if (self.disappearingMessagesConfiguration.isEnabled) {
NSString *keepForFormat = NSLocalizedString(@"KEEP_MESSAGES_DURATION",
@"Slider label embeds {{TIME_AMOUNT}}, e.g. '2 hours'. See *_TIME_AMOUNT strings for examples.");
self.disappearingMessagesDurationLabel.text =
[NSString stringWithFormat:keepForFormat, self.disappearingMessagesConfiguration.durationString];
} else {
self.disappearingMessagesDurationLabel.text
= NSLocalizedString(@"KEEP_MESSAGES_FOREVER", @"Slider label when disappearing messages is off");
}
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender
{
if ([segue.destinationViewController isKindOfClass:[FingerprintViewController class]]) {
FingerprintViewController *controller = (FingerprintViewController *)segue.destinationViewController;
OWSFingerprintBuilder *fingerprintBuilder =
[[OWSFingerprintBuilder alloc] initWithStorageManager:self.storageManager];
OWSFingerprint *fingerprint = [fingerprintBuilder fingerprintWithTheirSignalId:self.thread.contactIdentifier];
[controller configureWithThread:self.thread fingerprint:fingerprint contactName:self.contactName];
controller.dismissDelegate = self;
} else if ([segue.identifier isEqualToString:OWSConversationSettingsTableViewControllerSegueUpdateGroup]) {
NewGroupViewController *vc = [segue destinationViewController];
[vc configWithThread:(TSGroupThread *)self.thread];
} else if ([segue.identifier isEqualToString:OWSConversationSettingsTableViewControllerSegueShowGroupMembers]) {
ShowGroupMembersViewController *vc = [segue destinationViewController];
[vc configWithThread:(TSGroupThread *)self.thread];
}
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -59,8 +59,6 @@ int const OWSLinkedDevicesTableViewControllerSectionAddDevice = 1;
[self.refreshControl addTarget:self action:@selector(refreshDevices) forControlEvents:UIControlEventValueChanged]; [self.refreshControl addTarget:self action:@selector(refreshDevices) forControlEvents:UIControlEventValueChanged];
[self setupEditButton]; [self setupEditButton];
// So we can still tap on "add new device"
self.tableView.allowsSelectionDuringEditing = YES;
} }
- (void)viewWillAppear:(BOOL)animated - (void)viewWillAppear:(BOOL)animated

View File

@ -7,9 +7,9 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "APNavigationController.h"
#import "TSSocketManager.h" #import "TSSocketManager.h"
@interface SignalsNavigationController : APNavigationController
@interface SignalsNavigationController : UINavigationController
@property (nonatomic, strong) UIProgressView *socketStatusView; @property (nonatomic, strong) UIProgressView *socketStatusView;
@property (nonatomic, strong) NSTimer *updateStatusTimer; @property (nonatomic, strong) NSTimer *updateStatusTimer;
@end @end

View File

@ -39,12 +39,39 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
@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;
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@end @end
@implementation SignalsViewController @implementation SignalsViewController
- (void)awakeFromNib { - (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_contactsManager = [Environment getCurrent].contactsManager;
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
_contactsManager = [Environment getCurrent].contactsManager;
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
[[Environment getCurrent] setSignalsViewController:self]; [[Environment getCurrent] setSignalsViewController:self];
} }
@ -172,7 +199,7 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
} }
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cell configureWithThread:thread]; [cell configureWithThread:thread contactsManager:self.contactsManager];
}); });
if ((unsigned long)indexPath.row == [self.threadMappings numberOfItemsInSection:0] - 1) { if ((unsigned long)indexPath.row == [self.threadMappings numberOfItemsInSection:0] - 1) {

View File

@ -5,12 +5,11 @@
#import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h> #import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
static const CGFloat OWSDisplayedMessageCellHeight = 70.0f; extern const CGFloat OWSDisplayedMessageCellMinimumHeight;
@interface OWSDisplayedMessageCollectionViewCell : JSQMessagesCollectionViewCell @interface OWSDisplayedMessageCollectionViewCell : JSQMessagesCollectionViewCell
@property (weak, nonatomic, readonly) JSQMessagesLabel *cellLabel; @property (weak, nonatomic, readonly) JSQMessagesLabel *cellLabel;
@property (weak, nonatomic, readonly) UIImageView *headerImageView; @property (weak, nonatomic, readonly) UIImageView *headerImageView;
@property (strong, nonatomic, readonly) UIView *textContainer;
@end @end

View File

@ -6,12 +6,13 @@
#import <JSQMessagesViewController/UIView+JSQMessages.h> #import <JSQMessagesViewController/UIView+JSQMessages.h>
const CGFloat OWSDisplayedMessageCellMinimumHeight = 70.0;
@interface OWSDisplayedMessageCollectionViewCell () @interface OWSDisplayedMessageCollectionViewCell ()
@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel; @property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellTopLabelHeightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellTopLabelHeightConstraint;
@property (weak, nonatomic) IBOutlet UIImageView *headerImageView; @property (weak, nonatomic) IBOutlet UIImageView *headerImageView;
@property (strong, nonatomic) IBOutlet UIView *textContainer;
@end @end
@ -39,12 +40,10 @@
self.backgroundColor = [UIColor whiteColor]; self.backgroundColor = [UIColor whiteColor];
self.textContainer.layer.borderColor = [[UIColor lightGrayColor] CGColor]; self.messageBubbleContainerView.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.textContainer.layer.borderWidth = 0.75f; self.messageBubbleContainerView.layer.borderWidth = 0.75f;
self.textContainer.layer.cornerRadius = 5.0f; self.messageBubbleContainerView.layer.cornerRadius = 5.0f;
self.cellLabel.textAlignment = NSTextAlignmentCenter; self.cellLabel.textColor = [UIColor darkGrayColor];
self.cellLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
self.cellLabel.textColor = [UIColor lightGrayColor];
} }
#pragma mark - Collection view cell #pragma mark - Collection view cell
@ -56,13 +55,4 @@
self.cellLabel.text = nil; self.cellLabel.text = nil;
} }
// This subclass does not have a messageBubbleContainerView, so superclass
// touch calculations will be incorrect. Since this view spans the entire
// frame, we can override the touch handler to respond to user actions by
// default.
- (void)jsq_handleTapGesture:(UITapGestureRecognizer *)tap
{
[self.delegate messagesCollectionViewCellDidTapMessageBubble:self];
}
@end @end

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/> <capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@ -16,8 +17,7 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gcR-Rk-KDC" userLabel="Cell top label" customClass="JSQMessagesLabel"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gcR-Rk-KDC" userLabel="Cell top label" customClass="JSQMessagesLabel">
<rect key="frame" x="0.0" y="0.0" width="320" height="20"/> <color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="20" id="ckj-xD-FJI"/> <constraint firstAttribute="height" constant="20" id="ckj-xD-FJI"/>
</constraints> </constraints>
@ -25,20 +25,18 @@
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/> <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qCf-bs-dBd" userLabel="textContainer"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qCf-bs-dBd" userLabel="Bubble container">
<rect key="frame" x="0.0" y="42" width="320" height="48"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info Message" textAlignment="center" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" numberOfLines="0" translatesAutoresizingMaskIntoConstraints="NO" id="OVa-Xw-5vl" customClass="JSQMessagesLabel"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info Message" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="OVa-Xw-5vl" customClass="JSQMessagesLabel">
<rect key="frame" x="8" y="12" width="304" height="28"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="14" id="fed-2c-dqd"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="14" id="fed-2c-dqd"/>
</constraints> </constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="OVa-Xw-5vl" firstAttribute="leading" secondItem="qCf-bs-dBd" secondAttribute="leading" constant="8" id="2IE-8k-czI"/> <constraint firstItem="OVa-Xw-5vl" firstAttribute="leading" secondItem="qCf-bs-dBd" secondAttribute="leading" constant="8" id="2IE-8k-czI"/>
<constraint firstAttribute="bottom" secondItem="OVa-Xw-5vl" secondAttribute="bottom" constant="8" id="MtI-jW-t1x"/> <constraint firstAttribute="bottom" secondItem="OVa-Xw-5vl" secondAttribute="bottom" constant="8" id="MtI-jW-t1x"/>
@ -47,14 +45,12 @@
</constraints> </constraints>
</view> </view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="warning_white.png" translatesAutoresizingMaskIntoConstraints="NO" id="ePO-Cy-jUE"> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="warning_white.png" translatesAutoresizingMaskIntoConstraints="NO" id="ePO-Cy-jUE">
<rect key="frame" x="143" y="20" width="35" height="35"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="35" id="Llx-81-oyV"/> <constraint firstAttribute="height" constant="35" id="Llx-81-oyV"/>
<constraint firstAttribute="width" constant="35" id="Nth-3D-Wo9"/> <constraint firstAttribute="width" constant="35" id="Nth-3D-Wo9"/>
</constraints> </constraints>
</imageView> </imageView>
</subviews> </subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view> </view>
<constraints> <constraints>
<constraint firstItem="ePO-Cy-jUE" firstAttribute="top" secondItem="gcR-Rk-KDC" secondAttribute="bottom" id="1yH-xH-np2"/> <constraint firstItem="ePO-Cy-jUE" firstAttribute="top" secondItem="gcR-Rk-KDC" secondAttribute="bottom" id="1yH-xH-np2"/>
@ -73,7 +69,7 @@
<outlet property="cellTopLabel" destination="gcR-Rk-KDC" id="Ogk-hD-ge8"/> <outlet property="cellTopLabel" destination="gcR-Rk-KDC" id="Ogk-hD-ge8"/>
<outlet property="cellTopLabelHeightConstraint" destination="ckj-xD-FJI" id="wBH-pQ-Wc7"/> <outlet property="cellTopLabelHeightConstraint" destination="ckj-xD-FJI" id="wBH-pQ-Wc7"/>
<outlet property="headerImageView" destination="ePO-Cy-jUE" id="4uq-2C-V7U"/> <outlet property="headerImageView" destination="ePO-Cy-jUE" id="4uq-2C-V7U"/>
<outlet property="textContainer" destination="qCf-bs-dBd" id="fL7-LO-El1"/> <outlet property="messageBubbleContainerView" destination="qCf-bs-dBd" id="WMx-Di-LZG"/>
</connections> </connections>
<point key="canvasLocation" x="219" y="433"/> <point key="canvasLocation" x="219" y="433"/>
</collectionViewCell> </collectionViewCell>

View File

@ -0,0 +1,20 @@
// Created by Michael Kirk on 9/29/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
NS_ASSUME_NONNULL_BEGIN
@class OWSExpirationTimerView;
static const CGFloat OWSExpirableMessageViewTimerWidth = 10.0f;
@protocol OWSExpirableMessageView
@property (strong, nonatomic, readonly) IBOutlet OWSExpirationTimerView *expirationTimerView;
@property (strong, nonatomic, readonly) IBOutlet NSLayoutConstraint *expirationTimerViewWidthConstraint;
- (void)startExpirationTimerWithExpiresAtSeconds:(uint64_t)expiresAtSeconds
initialDurationSeconds:(uint32_t)initialDurationSeconds;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,17 @@
// Created by Michael Kirk on 9/29/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSExpirationTimerView : UIView
- (void)startTimerWithExpiresAtSeconds:(uint64_t)expiresAtSeconds
initialDurationSeconds:(uint32_t)initialDurationSeconds;
- (void)stopBlinking;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,184 @@
// Created by Michael Kirk on 9/29/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSExpirationTimerView.h"
#import "MessagesViewController.h"
#import "UIColor+OWS.h"
#import <QuartzCore/CAShapeLayer.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSExpirationTimerView ()
@property (nonatomic) uint32_t initialDurationSeconds;
@property (atomic) uint64_t expiresAtSeconds;
@property (nonatomic, readonly) UIImageView *emptyHourglassImageView;
@property (nonatomic, readonly) UIImageView *fullHourglassImageView;
@property CGFloat ratioRemaining;
@end
@implementation OWSExpirationTimerView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
return self;
}
self.clipsToBounds = YES;
_emptyHourglassImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_hourglass_empty"]];
_emptyHourglassImageView.tintColor = [UIColor ows_blackColor];
[self insertSubview:_emptyHourglassImageView atIndex:0];
_fullHourglassImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_hourglass_full"]];
_fullHourglassImageView.tintColor = [UIColor ows_darkGrayColor];
[self insertSubview:_fullHourglassImageView atIndex:1];
_ratioRemaining = 1.0f;
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
self.clipsToBounds = YES;
_emptyHourglassImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_hourglass_empty"]];
_emptyHourglassImageView.tintColor = [UIColor lightGrayColor];
[self insertSubview:_emptyHourglassImageView atIndex:1];
_fullHourglassImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_hourglass_full"]];
_fullHourglassImageView.tintColor = [UIColor lightGrayColor];
[self insertSubview:_fullHourglassImageView atIndex:0];
_ratioRemaining = 1.0f;
return self;
}
- (void)layoutSubviews
{
CGFloat leftMargin = 0.0f;
CGFloat padding = 6.0f;
CGRect hourglassFrame
= CGRectMake(leftMargin, padding / 2, self.frame.size.height - padding, self.frame.size.height - padding);
self.emptyHourglassImageView.frame = hourglassFrame;
self.emptyHourglassImageView.bounds = hourglassFrame;
self.fullHourglassImageView.frame = hourglassFrame;
self.fullHourglassImageView.bounds = hourglassFrame;
}
- (void)restartAnimation:(NSNotification *)notification
{
[self startTimerWithExpiresAtSeconds:self.expiresAtSeconds initialDurationSeconds:self.initialDurationSeconds];
}
- (void)startTimerWithExpiresAtSeconds:(uint64_t)expiresAtSeconds
initialDurationSeconds:(uint32_t)initialDurationSeconds
{
if (expiresAtSeconds == 0) {
DDLogWarn(
@"%@ Asked to animate expiration for message which hasn't started expiring. intitialDurationSeconds:%u",
self.logTag,
initialDurationSeconds);
}
DDLogVerbose(@"%@ Starting animation timer with expiresAtSeconds: %llu initialDurationSeconds: %d",
self.logTag,
expiresAtSeconds,
initialDurationSeconds);
self.expiresAtSeconds = expiresAtSeconds;
self.initialDurationSeconds = initialDurationSeconds;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(restartAnimation:)
name:OWSMessagesViewControllerDidAppearNotification
object:nil];
double secondsLeft = (double)self.expiresAtSeconds - [NSDate new].timeIntervalSince1970;
if (secondsLeft < 0) {
secondsLeft = 0;
}
// Get hourglass frames to the proper size.
[self setNeedsLayout];
[self layoutIfNeeded];
CAGradientLayer *maskLayer = [CAGradientLayer new];
self.fullHourglassImageView.layer.mask = maskLayer;
maskLayer.frame = self.fullHourglassImageView.frame;
// Blur the top of the mask a bit with gradient
maskLayer.colors = @[ (id)[UIColor clearColor].CGColor, (id)[UIColor blackColor].CGColor ];
maskLayer.startPoint = CGPointMake(0.5f, 0);
maskLayer.endPoint = CGPointMake(0.5f, 0.2f);
CGFloat ratioRemaining = ((CGFloat)secondsLeft / (CGFloat)self.initialDurationSeconds);
if (ratioRemaining < 0) {
ratioRemaining = 0.0;
}
CGPoint defaultPosition = maskLayer.position;
CGPoint finalPosition = CGPointMake(defaultPosition.x, defaultPosition.y + maskLayer.bounds.size.height);
CGPoint startingPosition
= CGPointMake(defaultPosition.x, finalPosition.y - maskLayer.bounds.size.height * ratioRemaining);
maskLayer.position = startingPosition;
CABasicAnimation *revealAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
revealAnimation.duration = secondsLeft;
revealAnimation.fromValue = [NSValue valueWithCGPoint:startingPosition];
revealAnimation.toValue = [NSValue valueWithCGPoint:finalPosition];
[maskLayer addAnimation:revealAnimation forKey:@"revealAnimation"];
maskLayer.position = finalPosition; // don't snap back
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ((long long)secondsLeft - 2) * (long long)NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
[self startBlinking];
});
}
- (void)startBlinking
{
CABasicAnimation *blinkAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
blinkAnimation.duration = 0.5;
blinkAnimation.fromValue = @(1.0);
blinkAnimation.toValue = @(0.0);
blinkAnimation.repeatCount = 4;
blinkAnimation.autoreverses = YES;
blinkAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.layer addAnimation:blinkAnimation forKey:@"alphaBlink"];
}
- (void)stopBlinking
{
[self.layer removeAnimationForKey:@"alphaBlink"];
self.layer.opacity = 1;
}
#pragma mark - Logging
+ (NSString *)logTag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)logTag
{
return self.class.logTag;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,13 @@
// Created by Michael Kirk on 9/29/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSExpirableMessageView.h"
#import <JSQMessagesViewController/JSQMessagesCollectionViewCellIncoming.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSIncomingMessageCollectionViewCell : JSQMessagesCollectionViewCellIncoming <OWSExpirableMessageView>
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,43 @@
// Created by Michael Kirk on 9/29/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSIncomingMessageCollectionViewCell.h"
#import "OWSExpirationTimerView.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSIncomingMessageCollectionViewCell ()
@property (strong, nonatomic) IBOutlet OWSExpirationTimerView *expirationTimerView;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *expirationTimerViewWidthConstraint;
@end
@implementation OWSIncomingMessageCollectionViewCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.expirationTimerViewWidthConstraint.constant = 0.0;
}
- (void)prepareForReuse
{
[super prepareForReuse];
[self.expirationTimerView stopBlinking];
self.expirationTimerViewWidthConstraint.constant = 0.0f;
}
// pragma mark - OWSExpirableMessageView
- (void)startExpirationTimerWithExpiresAtSeconds:(uint64_t)expiresAtSeconds
initialDurationSeconds:(uint32_t)initialDurationSeconds
{
self.expirationTimerViewWidthConstraint.constant = OWSExpirableMessageViewTimerWidth;
[self.expirationTimerView startTimerWithExpiresAtSeconds:expiresAtSeconds
initialDurationSeconds:initialDurationSeconds];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="" id="4lh-CK-yVn" customClass="OWSIncomingMessageCollectionViewCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="afj-rd-iNv" userLabel="Cell top label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="fKS-MR-YPI"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="bubble top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ufa-bF-l1Y" userLabel="Bubble top label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="fal-sy-hrK"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="btS-p8-B7Z" userLabel="Bubble container">
<frame key="frameInset" minX="36" minY="40" width="244" height="94"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OCS-Fu-acq" userLabel="Bubble Image View">
<frame key="frameInset" width="244" height="94"/>
</imageView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KYU-B8-cUW" customClass="JSQMessagesCellTextView">
<frame key="frameInset" minX="6" width="238" height="94"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="KYU-B8-cUW" secondAttribute="trailing" id="4qS-03-PFO"/>
<constraint firstAttribute="bottom" secondItem="KYU-B8-cUW" secondAttribute="bottom" id="B2v-Gq-Y1L"/>
<constraint firstAttribute="trailing" secondItem="OCS-Fu-acq" secondAttribute="trailing" id="TdB-8V-aUc"/>
<constraint firstItem="KYU-B8-cUW" firstAttribute="leading" secondItem="btS-p8-B7Z" secondAttribute="leading" constant="6" id="Tg9-9l-vr8"/>
<constraint firstItem="KYU-B8-cUW" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="aEL-yH-N1p"/>
<constraint firstAttribute="bottom" secondItem="OCS-Fu-acq" secondAttribute="bottom" id="aJ4-ZD-tk9"/>
<constraint firstItem="OCS-Fu-acq" firstAttribute="leading" secondItem="btS-p8-B7Z" secondAttribute="leading" id="qpQ-dc-2V5"/>
<constraint firstAttribute="width" constant="244" id="stE-iz-VHo"/>
<constraint firstItem="OCS-Fu-acq" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="zTa-8g-VY4"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Da1-09-wR4" userLabel="Avatar container">
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="w23-sL-0Rh" userLabel="Avatar Image View"/>
</subviews>
<color key="backgroundColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="w23-sL-0Rh" firstAttribute="leading" secondItem="Da1-09-wR4" secondAttribute="leading" id="6zm-sH-cOT"/>
<constraint firstAttribute="trailing" secondItem="w23-sL-0Rh" secondAttribute="trailing" id="JgK-7W-L10"/>
<constraint firstAttribute="bottom" secondItem="w23-sL-0Rh" secondAttribute="bottom" id="U39-Ze-JZ6"/>
<constraint firstAttribute="width" constant="34" id="YwX-fW-Me6"/>
<constraint firstItem="w23-sL-0Rh" firstAttribute="top" secondItem="Da1-09-wR4" secondAttribute="top" id="hxb-KR-hNK"/>
<constraint firstAttribute="height" constant="34" id="tZk-AK-JFa"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0eu-Z9-ndP" userLabel="Footer Container">
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell bottom label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UPz-5x-c1T" userLabel="Cell bottom label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="xPR-Ph-Ze9"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UYa-ee-mie" userLabel="Expiration Timer" customClass="OWSExpirationTimerView">
<constraints>
<constraint firstAttribute="width" constant="10" id="Spx-mv-2DX"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="UPz-5x-c1T" secondAttribute="bottom" id="3hV-mq-Bcf"/>
<constraint firstItem="UPz-5x-c1T" firstAttribute="top" secondItem="0eu-Z9-ndP" secondAttribute="top" id="7v5-pU-s1n"/>
<constraint firstAttribute="trailing" secondItem="UPz-5x-c1T" secondAttribute="trailing" id="TlZ-tg-six"/>
<constraint firstItem="UPz-5x-c1T" firstAttribute="leading" secondItem="UYa-ee-mie" secondAttribute="trailing" id="WVv-6q-I5l"/>
<constraint firstAttribute="bottom" secondItem="UYa-ee-mie" secondAttribute="bottom" id="fVy-Bf-ePa"/>
<constraint firstItem="UYa-ee-mie" firstAttribute="top" secondItem="0eu-Z9-ndP" secondAttribute="top" id="iHb-8v-vc4"/>
<constraint firstItem="UYa-ee-mie" firstAttribute="leading" secondItem="0eu-Z9-ndP" secondAttribute="leading" id="p2g-wW-Ra6"/>
<constraint firstAttribute="height" secondItem="UPz-5x-c1T" secondAttribute="height" id="vbI-L6-mkn"/>
</constraints>
</view>
</subviews>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="0eu-Z9-ndP" secondAttribute="trailing" id="JeQ-cB-BZe"/>
<constraint firstAttribute="trailing" secondItem="afj-rd-iNv" secondAttribute="trailing" id="Ka4-Dy-jCS"/>
<constraint firstItem="0eu-Z9-ndP" firstAttribute="top" secondItem="Da1-09-wR4" secondAttribute="bottom" id="Mxx-Zi-4pN"/>
<constraint firstItem="afj-rd-iNv" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="OnD-mZ-QtR"/>
<constraint firstAttribute="bottom" secondItem="0eu-Z9-ndP" secondAttribute="bottom" id="VPM-Vk-cDj"/>
<constraint firstItem="Ufa-bF-l1Y" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="Z5z-m3-8Ne"/>
<constraint firstItem="afj-rd-iNv" firstAttribute="top" secondItem="4lh-CK-yVn" secondAttribute="top" id="ZG9-2M-N52"/>
<constraint firstAttribute="trailing" secondItem="Ufa-bF-l1Y" secondAttribute="trailing" id="cWQ-1Q-xOA"/>
<constraint firstItem="Ufa-bF-l1Y" firstAttribute="top" secondItem="afj-rd-iNv" secondAttribute="bottom" id="i9Y-sV-v6b"/>
<constraint firstItem="btS-p8-B7Z" firstAttribute="leading" secondItem="Da1-09-wR4" secondAttribute="trailing" constant="2" id="j0I-pm-eex"/>
<constraint firstItem="btS-p8-B7Z" firstAttribute="top" secondItem="Ufa-bF-l1Y" secondAttribute="bottom" id="jAu-Dn-7rN"/>
<constraint firstItem="Da1-09-wR4" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="jiu-B4-TSD"/>
<constraint firstItem="0eu-Z9-ndP" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" constant="10" id="kwA-RP-CSv"/>
</constraints>
<size key="customSize" width="317" height="245"/>
<connections>
<outlet property="avatarContainerView" destination="Da1-09-wR4" id="tpM-P4-qUR"/>
<outlet property="avatarContainerViewHeightConstraint" destination="tZk-AK-JFa" id="tPu-mC-ITh"/>
<outlet property="avatarContainerViewWidthConstraint" destination="YwX-fW-Me6" id="5PN-NL-hEP"/>
<outlet property="avatarImageView" destination="w23-sL-0Rh" id="Yf4-UR-VRC"/>
<outlet property="cellBottomLabel" destination="UPz-5x-c1T" id="MKm-hp-T6v"/>
<outlet property="cellBottomLabelHeightConstraint" destination="xPR-Ph-Ze9" id="nvV-Tk-AIs"/>
<outlet property="cellTopLabel" destination="afj-rd-iNv" id="bTd-4q-U7e"/>
<outlet property="cellTopLabelHeightConstraint" destination="fKS-MR-YPI" id="YWd-Rd-qSL"/>
<outlet property="expirationTimerView" destination="UYa-ee-mie" id="y5V-L9-vWJ"/>
<outlet property="expirationTimerViewWidthConstraint" destination="Spx-mv-2DX" id="ebW-8s-AfN"/>
<outlet property="messageBubbleContainerView" destination="btS-p8-B7Z" id="2sk-5p-NEd"/>
<outlet property="messageBubbleContainerWidthConstraint" destination="stE-iz-VHo" id="lle-iT-67d"/>
<outlet property="messageBubbleImageView" destination="OCS-Fu-acq" id="OuN-5t-30g"/>
<outlet property="messageBubbleTopLabel" destination="Ufa-bF-l1Y" id="VtH-te-blR"/>
<outlet property="messageBubbleTopLabelHeightConstraint" destination="fal-sy-hrK" id="kgv-NO-Gud"/>
<outlet property="textView" destination="KYU-B8-cUW" id="1Yv-ln-EUZ"/>
<outlet property="textViewAvatarHorizontalSpaceConstraint" destination="Tg9-9l-vr8" id="HWn-aO-NbR"/>
<outlet property="textViewBottomVerticalSpaceConstraint" destination="B2v-Gq-Y1L" id="oKV-Ti-Oci"/>
<outlet property="textViewMarginHorizontalSpaceConstraint" destination="4qS-03-PFO" id="1Qe-Ee-fUO"/>
<outlet property="textViewTopVerticalSpaceConstraint" destination="aEL-yH-N1p" id="WPl-0b-tf1"/>
</connections>
<point key="canvasLocation" x="255" y="202"/>
</collectionViewCell>
</objects>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4_7.fullscreen"/>
</simulatedMetricsContainer>
</document>

View File

@ -0,0 +1,13 @@
// Created by Michael Kirk on 9/28/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSExpirableMessageView.h"
#import <JSQMessagesViewController/JSQMessagesCollectionViewCellOutgoing.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSOutgoingMessageCollectionViewCell : JSQMessagesCollectionViewCellOutgoing <OWSExpirableMessageView>
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,43 @@
// Created by Michael Kirk on 9/28/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSOutgoingMessageCollectionViewCell.h"
#import "OWSExpirationTimerView.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSOutgoingMessageCollectionViewCell ()
@property (strong, nonatomic) IBOutlet OWSExpirationTimerView *expirationTimerView;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *expirationTimerViewWidthConstraint;
@end
@implementation OWSOutgoingMessageCollectionViewCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.expirationTimerViewWidthConstraint.constant = 0.0;
}
- (void)prepareForReuse
{
[super prepareForReuse];
[self.expirationTimerView stopBlinking];
self.expirationTimerViewWidthConstraint.constant = 0.0f;
}
// pragma mark - OWSExpirableMessageView
- (void)startExpirationTimerWithExpiresAtSeconds:(uint64_t)expiresAtSeconds
initialDurationSeconds:(uint32_t)initialDurationSeconds
{
self.expirationTimerViewWidthConstraint.constant = OWSExpirableMessageViewTimerWidth;
[self.expirationTimerView startTimerWithExpiresAtSeconds:expiresAtSeconds
initialDurationSeconds:initialDurationSeconds];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="" id="23f-xH-rkY" customClass="OWSOutgoingMessageCollectionViewCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jxM-YD-sVG" userLabel="Cell top label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="9oK-E7-iXA"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="bubble top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p52-YN-yLu" userLabel="Bubble top label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="8TB-va-f8L"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2zh-vR-QJW" userLabel="Bubble container">
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2qm-c6-OZf" userLabel="Bubble Image View"/>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vLY-aM-0Dr" customClass="JSQMessagesCellTextView">
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="vLY-aM-0Dr" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="leading" id="7rI-Nc-AK3"/>
<constraint firstAttribute="trailing" secondItem="2qm-c6-OZf" secondAttribute="trailing" id="AEu-1l-tqh"/>
<constraint firstItem="2qm-c6-OZf" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="top" id="DbW-Cx-zOW"/>
<constraint firstItem="2qm-c6-OZf" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="leading" id="H1H-yn-Raq"/>
<constraint firstItem="vLY-aM-0Dr" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="top" id="RiG-21-Bqc"/>
<constraint firstAttribute="bottom" secondItem="vLY-aM-0Dr" secondAttribute="bottom" id="UbF-Bl-Q7v"/>
<constraint firstAttribute="trailing" secondItem="vLY-aM-0Dr" secondAttribute="trailing" constant="6" id="aVg-yy-8K7"/>
<constraint firstAttribute="width" constant="244" id="imD-52-K45"/>
<constraint firstAttribute="bottom" secondItem="2qm-c6-OZf" secondAttribute="bottom" id="lts-Ve-wSh"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X89-B1-aAd" userLabel="Avatar container">
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="y9b-D9-Q7W" userLabel="Avatar Image View"/>
</subviews>
<color key="backgroundColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="y9b-D9-Q7W" secondAttribute="bottom" id="7SX-4t-GAr"/>
<constraint firstAttribute="width" constant="34" id="Pkm-tW-k4z"/>
<constraint firstItem="y9b-D9-Q7W" firstAttribute="leading" secondItem="X89-B1-aAd" secondAttribute="leading" id="Pya-tL-FjE"/>
<constraint firstItem="y9b-D9-Q7W" firstAttribute="top" secondItem="X89-B1-aAd" secondAttribute="top" id="e5w-hn-mre"/>
<constraint firstAttribute="height" constant="34" id="tgw-aN-JJu"/>
<constraint firstAttribute="trailing" secondItem="y9b-D9-Q7W" secondAttribute="trailing" id="w9X-3u-BNY"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wFK-dt-TWZ" userLabel="Footer Container">
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell bottom label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Uc-dI-YDD" userLabel="Cell bottom label" customClass="JSQMessagesLabel">
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="cPs-M4-tjX"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0tt-tR-3Iu" userLabel="Expiration Timer" customClass="OWSExpirationTimerView">
<constraints>
<constraint firstAttribute="width" constant="10" id="5XO-l6-PgT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="0tt-tR-3Iu" firstAttribute="leading" secondItem="7Uc-dI-YDD" secondAttribute="trailing" id="3rd-VE-2kc"/>
<constraint firstItem="7Uc-dI-YDD" firstAttribute="leading" secondItem="wFK-dt-TWZ" secondAttribute="leading" id="8bH-5V-WeT"/>
<constraint firstItem="7Uc-dI-YDD" firstAttribute="top" secondItem="wFK-dt-TWZ" secondAttribute="top" id="HU0-Ql-nzh"/>
<constraint firstAttribute="bottom" secondItem="7Uc-dI-YDD" secondAttribute="bottom" id="aG2-Au-de4"/>
<constraint firstItem="0tt-tR-3Iu" firstAttribute="top" secondItem="wFK-dt-TWZ" secondAttribute="top" id="cWj-FU-zAs"/>
<constraint firstAttribute="bottom" secondItem="0tt-tR-3Iu" secondAttribute="bottom" id="d3u-eO-0Vh"/>
<constraint firstAttribute="trailing" secondItem="0tt-tR-3Iu" secondAttribute="trailing" id="ikV-vO-dvu"/>
<constraint firstItem="7Uc-dI-YDD" firstAttribute="height" secondItem="wFK-dt-TWZ" secondAttribute="height" id="tBD-NV-24p"/>
</constraints>
</view>
</subviews>
</view>
<constraints>
<constraint firstItem="wFK-dt-TWZ" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="3WR-qA-BlN"/>
<constraint firstItem="2zh-vR-QJW" firstAttribute="top" secondItem="p52-YN-yLu" secondAttribute="bottom" id="3Wx-g0-fTc"/>
<constraint firstAttribute="trailing" secondItem="jxM-YD-sVG" secondAttribute="trailing" id="AwY-g7-f1T"/>
<constraint firstItem="wFK-dt-TWZ" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="bottom" id="Ckg-Bj-HXn"/>
<constraint firstItem="jxM-YD-sVG" firstAttribute="top" secondItem="23f-xH-rkY" secondAttribute="top" id="HYT-Tw-whz"/>
<constraint firstAttribute="trailing" secondItem="X89-B1-aAd" secondAttribute="trailing" id="KLt-Ix-wDa"/>
<constraint firstAttribute="bottom" secondItem="wFK-dt-TWZ" secondAttribute="bottom" id="g9n-w3-IXp"/>
<constraint firstAttribute="trailing" secondItem="p52-YN-yLu" secondAttribute="trailing" id="gen-N0-uZj"/>
<constraint firstItem="wFK-dt-TWZ" firstAttribute="top" secondItem="X89-B1-aAd" secondAttribute="bottom" id="hNe-hv-ytt"/>
<constraint firstItem="p52-YN-yLu" firstAttribute="top" secondItem="jxM-YD-sVG" secondAttribute="bottom" id="jBD-JV-AWk"/>
<constraint firstItem="jxM-YD-sVG" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="qeB-G5-1Wq"/>
<constraint firstAttribute="trailing" secondItem="wFK-dt-TWZ" secondAttribute="trailing" constant="10" id="r4Q-Yj-BY6"/>
<constraint firstItem="p52-YN-yLu" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="tTj-Mp-0va"/>
<constraint firstItem="X89-B1-aAd" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="trailing" constant="2" id="vMz-Yi-B0w"/>
</constraints>
<size key="customSize" width="317" height="245"/>
<connections>
<outlet property="avatarContainerView" destination="X89-B1-aAd" id="WSI-Zc-qIE"/>
<outlet property="avatarContainerViewHeightConstraint" destination="tgw-aN-JJu" id="pgV-tY-5Cm"/>
<outlet property="avatarContainerViewWidthConstraint" destination="Pkm-tW-k4z" id="Cpe-d3-yiq"/>
<outlet property="avatarImageView" destination="y9b-D9-Q7W" id="cZo-SR-S9h"/>
<outlet property="cellBottomLabel" destination="7Uc-dI-YDD" id="gVD-C2-UcZ"/>
<outlet property="cellBottomLabelHeightConstraint" destination="cPs-M4-tjX" id="b5k-6e-iA8"/>
<outlet property="cellTopLabel" destination="jxM-YD-sVG" id="acH-pr-spx"/>
<outlet property="cellTopLabelHeightConstraint" destination="9oK-E7-iXA" id="MZM-kV-2dI"/>
<outlet property="expirationTimerView" destination="0tt-tR-3Iu" id="1Yp-Fs-DUh"/>
<outlet property="expirationTimerViewWidthConstraint" destination="5XO-l6-PgT" id="6md-KV-QkY"/>
<outlet property="messageBubbleContainerView" destination="2zh-vR-QJW" id="pu0-GU-eZl"/>
<outlet property="messageBubbleContainerWidthConstraint" destination="imD-52-K45" id="Xld-Pa-yJw"/>
<outlet property="messageBubbleImageView" destination="2qm-c6-OZf" id="bpy-Gv-jSh"/>
<outlet property="messageBubbleTopLabel" destination="p52-YN-yLu" id="SLH-sA-Chu"/>
<outlet property="messageBubbleTopLabelHeightConstraint" destination="8TB-va-f8L" id="FNt-BS-Wxi"/>
<outlet property="textView" destination="vLY-aM-0Dr" id="YEp-mW-xIY"/>
<outlet property="textViewAvatarHorizontalSpaceConstraint" destination="aVg-yy-8K7" id="CIe-Bi-eng"/>
<outlet property="textViewBottomVerticalSpaceConstraint" destination="UbF-Bl-Q7v" id="KHP-49-3u4"/>
<outlet property="textViewMarginHorizontalSpaceConstraint" destination="7rI-Nc-AK3" id="ciu-j6-IpH"/>
<outlet property="textViewTopVerticalSpaceConstraint" destination="RiG-21-Bqc" id="i3j-z0-feE"/>
</connections>
<point key="canvasLocation" x="371" y="145"/>
</collectionViewCell>
</objects>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4_7.fullscreen"/>
</simulatedMetricsContainer>
</document>

View File

@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -x
function usage() {
cat <<EOS
Extracts string from target file and appends to Localizable.strings
$0 <filename.m>
e.g.
$0 path/to/my/ClassName.m
EOS
}
BIN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $BIN_DIR/..
TARGET=$1
if [[ -z $TARGET ]]
then
echo "Can't proceed without target"
usage
exit 1
fi
if [[ ! -e $TARGET ]]
then
echo "No file exists at ${TARGET}"
exit 1
fi
# pwd.
OUTPUT_DIR=en.lproj/
mkdir -p "${OUTPUT_DIR}"
genstrings -a -o "${OUTPUT_DIR}" "${TARGET}"

View File

@ -1,27 +0,0 @@
#!/usr/bin/env bash
set -x
function usage() {
cat <<EOS
Extracts string from target file to new.strings
$0 <filename.m>
e.g.
$0 path/to/my/ClassName.m
EOS
}
TARGET=$1
if [[ -z $TARGET ]]
then
echo "Can't proceed without target"
usage
exit 1
fi
OUTPUT_DIR=new_strings
mkdir -p "${OUTPUT_DIR}"
genstrings -o "${OUTPUT_DIR}" "${TARGET}"

Some files were not shown because too many files have changed in this diff Show More