Compare commits

...

424 Commits

Author SHA1 Message Date
Michael Kirk
44b820ef5d Avoid iOS11 name collision
iOS11 introduced it's own `pasteDelegate` method on textView.

// FREEBIE
2017-09-06 09:28:47 -04:00
Matthew Chen
f9063f634f Merge branch 'charlesmchen/layoutGlitches' into signal-master 2017-08-31 16:35:01 -04:00
Matthew Chen
adbffe3e87 Preserve scroll state across conversation view layout changes, if possible.
// FREEBIE
2017-08-31 12:53:39 -04:00
Matthew Chen
f03e14f754 Observe layout changes in conversation view.
// FREEBIE
2017-08-31 12:39:07 -04:00
Matthew Chen
3f74b56ca7 Don't instantiate nib twice.
// FREEBIE
2017-08-31 12:37:44 -04:00
Matthew Chen
868cf70fae Merge branch 'charlesmchen/messageViewScrollStateRevisited' into signal-master 2017-08-29 11:23:53 -04:00
Matthew Chen
8ffe2518ef Revisit the [UIScrollView _adjustContentOffsetIfNecessary] issue.
// FREEBIE
2017-08-29 11:09:55 -04:00
Matthew Chen
9e452ee59c Merge branch 'charlesmchen/jsqTweaks' into signal-master 2017-08-25 16:56:53 -04:00
Matthew Chen
bb8ec4afcc Fix "scroll state flickers when presenting messages view" issue.
// FREEBIE
2017-08-25 16:56:42 -04:00
Matthew Chen
eb6205d0c9 Merge branch 'charlesmchen/ignoreSpuriousTraitCollectionChanges' into signal-master 2017-08-25 16:55:36 -04:00
Matthew Chen
221ad25fd7 Ignore spurious trait collection changes on view presentation.
// FREEBIE
2017-08-25 14:45:43 -04:00
Matthew Chen
d26758cd2b Merge branch 'charlesmchen/jsqRedundantLayout' into signal-master 2017-08-25 14:44:57 -04:00
Matthew Chen
06d5c6e646 Remove redundant view layout in JSQ view.
// FREEBIE
2017-08-25 13:11:52 -04:00
Michael Kirk
8c10f920bb Merge branch 'mkirk/fix-scrolling-crashes' into signal-master 2017-08-10 11:06:04 -04:00
Michael Kirk
146b84febc Fix scrolling crash
Don't touch the header zIndex at all, since we're not doing it
consistently, and we don't need it modified anyway.
2017-08-10 10:59:27 -04:00
Michael Kirk
7a7deff318 Adjusting insets should invalidate layout
Intended to fix crashes like these:

    Last Exception Backtrace:
    0   CoreFoundation   0x185818d5c __exceptionPreprocess + 124 (NSException.m:166)
    1   libobjc.A.dylib  0x184d2c528 objc_exception_throw + 56 (objc-exception.mm:521)
    2   CoreFoundation   0x185818c30 +[NSException raise:format:arguments:] + 104 (NSException.m:132)
    3   Foundation       0x1861a282c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 112 (NSException.m:157)
    4   UIKit            0x18f3a2814 __45-[UICollectionViewData validateLayoutInRect:]_block_invoke + 1500 (UICollectionViewData.m:447)
    5   UIKit            0x18f3a1c90 -[UICollectionViewData validateLayoutInRect:] + 1500 (UICollectionViewData.m:0)
    6   UIKit            0x18f3a10d0 -[UICollectionView layoutSubviews] + 260 (UICollectionView.m:3505)
    7   UIKit            0x18f343f50 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1256 (UIView.m:14894)
    8   QuartzCore       0x18994b670 -[CALayer layoutSublayers] + 184 (CALayer.mm:9200)
    9   QuartzCore       0x18994f748 CA::Layer::layout_if_needed(CA::Transaction*) + 332 (CALayer.mm:9080)
    10  UIKit            0x18f358dfc -[UIView(Hierarchy) layoutBelowIfNeeded] + 548 (UIView.m:10205)
    11  UIKit            0x18fd990b4 -[UICollectionView setContentInset:] + 92 (UICollectionView.m:4794)
    12  Signal           0x1032f1214 -[JSQMessagesViewController jsq_setCollectionViewInsetsTopValue:bottomValue:] + 88 (JSQMessagesViewController.m:1065)
    13  Signal           0x1032f1190 -[JSQMessagesViewController jsq_updateCollectionViewInsets] + 204 (JSQMessagesViewController.m:1058)
    14  Signal           0x1032e80ac -[JSQMessagesKeyboardController jsq_notifyKeyboardFrameNotificationForFrame:] + 120 (JSQMessagesKeyboardController.m:256)
    15  UIKit            0x18f37b6c4 +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 620 (UIView.m:12174)
    16  UIKit            0x18f391e6c +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 108 (UIView.m:12233)
    17  Signal           0x1032e7f0c -[JSQMessagesKeyboardController jsq_handleKeyboardNotification:completion:] + 576 (JSQMessagesKeyboardController.m:233)
2017-08-10 10:59:22 -04:00
Michael Kirk
560e59f8e4 Merge branch 'mkirk/use-signal-localizations' into signal-master 2017-07-21 14:15:39 -04:00
Michael Kirk
ef3bf46e9f Use Signal localizations.
The JSQMessagesViewController translations are incomplete, and it's much
simpler for our translators to translate in one place.
2017-07-20 18:02:15 -04:00
Admir Ireiz
5d7a5f99f9 Croatian localization 2017-07-18 18:11:40 -04:00
Michael Kirk
521686c112 remove unnecessary keyboard unassignment
Backstory is that in Signal we want to toggle the default keyboard.

To do this we dismiss and then pop the keyboard.

However, the event listeners cause an unsightly bounce animation when
this happens, so we'd temporarily disable the event listeners.

But then there is this side effect of unassigned the keyboard view when
toggling off the event listeners. There seems to be no reason for it.
(famous last words).

The consequence of unassigning the keyboard view was that future
calculations about keyboard dismissal were wrong, preventing you from
being able to dismiss the keyboard after sending a message.
2017-06-20 13:35:48 -04:00
Michael Kirk
7054e4b13e Position edit menu over media items properly. 2017-04-11 11:25:52 -04:00
J4awesome
fe656ae0c1 Update apps_using_this_library.md (#1896) 2016-11-11 15:38:31 -08:00
Jesse Squires
929f1d80cd update changelog and spec for 7.3.4 2016-07-20 21:47:01 -07:00
Michael Kirk
23bf3f0b1e Fix issue #1583: Don't highlight cell outside message bubble (when long press) (#1744)
In summary, overriden "touchesBegan" gaining all touch control of the JSQMessagesCollectionViewCell touches
2016-07-20 21:41:33 -07:00
Jesse Squires
e4927be6a8 update changelog and version for 7.3.3 2016-06-09 21:21:19 -07:00
GianniCarlo
0622f6f4d7 Updated canPerformAction:withSender: in JSQMessagesComposerTextView to call super (#1664). Fixes #1663. 2016-06-09 21:13:18 -07:00
Jesse Squires
ef5c87f0b4 Update CHANGELOG and version nums for 7.3.2 2016-06-05 16:29:18 -07:00
Jesse Squires
ed54d6c50d Merge branch 'master' of https://github.com/jessesquires/JSQMessagesViewController into release_7.3 2016-06-05 16:28:04 -07:00
Jesse Squires
e630340c48 fix KVO crash. close #1631 2016-06-05 16:21:57 -07:00
Jesse Squires
fa6917e4a8 formatting 2016-06-05 16:19:57 -07:00
IceFloe
25769603b7 small fix regarding scrollToIndexPath (#1642) close #1640 2016-06-05 16:18:38 -07:00
Jesse Squires
026b1e31f3 Update CHANGELOG.md 2016-05-30 15:36:38 -07:00
Jesse Squires
a430cbed21 update CHANGLOG. bump version numbers 2016-05-30 12:06:44 -07:00
sebastianludwig
d099c56c96 Reverted #1588 to fix #1602 and fix #1604. (#1623) 2016-05-30 11:57:37 -07:00
Jesse Squires
8c6e4081ff bump version numbers 2016-05-23 14:58:22 -07:00
Jesse Squires
7fdc6393c0 Update CHANGELOG.md 2016-05-23 14:54:28 -07:00
Jesse Squires
ade4e7a95d provide default init values for JSQMessagesCollectionViewLayoutAttributes to prevent assertion. fix #1338 2016-05-23 14:44:02 -07:00
Jesse Squires
9c435347af follow up for #1247 and #1591. obfuscate private APIs. swizzle via +initialize 2016-05-23 14:36:56 -07:00
Jesse Squires
5cb6acf71e copy attributes 2016-05-22 23:11:25 -07:00
Jesse Squires
66a54186da clean up 2016-05-22 22:17:42 -07:00
Xinyu Zhao
b7f487cc92 fix keyboard hiding bug on iOS 9 (#1307). fix #1063 2016-05-22 22:14:18 -07:00
Jesse Squires
8c29756211 - cleanup from PR #1281
- fix menu actions, close #1321
- make notification methods public
- partially apply changes from PR #1563
2016-05-22 22:02:29 -07:00
keyeMyria
2a46bd19b1 fix custom action show in JSQMessagesComposerTextView (#1281)
* fix custom action show in JSQMessagesComposerTextView. fixes #1234
2016-05-22 21:50:09 -07:00
Jesse Squires
6f4d6cc90c check data, not error 2016-05-22 21:33:53 -07:00
Jesse Squires
547e216e82 cleanup 2016-05-22 21:32:11 -07:00
Jesse Squires
c4143c59a5 fix iOS 9 crash when long pressing links in UITextView. close #1247 (#1591) 2016-05-22 21:30:22 -07:00
Jesse Squires
359d576668 Update CHANGELOG.md
close #1386
2016-05-22 19:29:00 -07:00
Roman Stetsenko
3b4dc8f238 Fixed bottom offset with transparent Tab Bar (#1588) 2016-05-22 19:17:05 -07:00
eliburke
40ae3b28c3 Flip the left and right insets on the audio message bubble based on message direction (#1590) 2016-05-22 19:10:06 -07:00
Jesse Squires
b53eef5dd8 Update CONDUCT.md 2016-05-21 12:00:20 -07:00
GianniCarlo
d0fea3d377 Update apps using this library file with Criptext (#1584) 2016-05-18 10:03:17 -07:00
Dan Leonard
c0928db9e1 Updating documentation to point to new swift example. (#1578) 2016-05-15 15:51:53 -07:00
Michael Tom
942ec7a016 Update apps_using_this_library.md (#1576) 2016-05-14 09:36:33 -07:00
Dan Leonard
aecb14f9b7 Swift example working (#1572)
* Initial Commit of Swift Implantation of JSQMessagesViewController. Project only as per @jessesquires request of doing small pull requests.

* adding test

* Add Icon

* Adding viewControllers to let you actually see JSQ in action in swift.
2016-05-11 22:48:14 -07:00
Dan Leonard
943d8d90ec Initial Commit of Swift Implantation of JSQMessagesViewController. Project only as per @jessesquires request of doing small pull requests. (#1568) 2016-05-10 09:36:30 -07:00
Jesse Squires
f867ce223f Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2016-05-02 07:56:47 -07:00
Jesse Squires
a6209a38f2 organization 2016-05-02 07:56:37 -07:00
Håkon Bertheussen
64dbe7f08b Added Norwegian translation of JSQMessages.strings (#1564) 2016-05-02 07:50:37 -07:00
Jesse Squires
532eb513a0 formatting cleanup 2016-04-29 08:51:24 -07:00
Jesse Squires
e32c63283d Update README.md 2016-04-28 19:28:27 -07:00
Jesse Squires
b959f61f82 Rename codecov.yml to .codecov.yml 2016-04-28 19:27:50 -07:00
Jesse Squires
99ff104590 Update codecov.yml 2016-04-26 09:10:22 -07:00
Jesse Squires
aa12e5d19b Update codecov.yml 2016-04-25 19:37:43 -07:00
BillCarsonFr
38e80c2696 [Accessibility] Make message view more voiceover friendly (#886)
- Cell is now accessible and will speak sender name and message
- Accessory button has now an accessibility label
- Post announcement when message is received
- Added accessibility label to toolbar’s text view
2016-04-20 11:15:16 -04:00
eliburke
d35bd59bce Audio settings (#1552) 2016-04-15 13:47:32 -07:00
GianniCarlo
0fef325f6a Fix crash in demo app on simulating incoming audio message (#1542)
closes #1541
2016-04-12 21:59:23 -07:00
eliburke
a1779e4a33 Demo audio item (#1540)
* fixed typo in author's name

* updated demo's actionsheet to send an audio item
2016-04-12 13:55:06 -04:00
Jesse Squires
959e07cceb Update README.md 2016-04-10 10:57:53 -07:00
Jesse Squires
8c6b123457 docs. 2016-04-06 21:38:20 -07:00
sebastianludwig
8cba6e5d7f Added method to scroll to a specific row, optionally animated. 2016-04-06 15:18:22 -07:00
Jesse Squires
f06c939b47 update spec 2016-04-06 09:24:47 -07:00
Jesse Squires
6873264627 clean up JSQAudioMediaItem. formatting, docs, nullablity. 2016-04-06 09:24:03 -07:00
Jesse Squires
d2e4a06115 clean up JSQAudioMediaViewAttributes. docs, designated initializer, immutable. 2016-04-06 08:41:34 -07:00
Błażej Biesiada
747bf802f2 Add Indonesian localization. 2016-04-05 09:35:19 -07:00
Błażej Biesiada
caeb91576f Add Malaysian localization. 2016-04-05 09:34:18 -07:00
eliburke
f656a7b129 Merge pull request #1495 from eliburke/audioMedia
Added JSQAudioMediaItem class
2016-04-05 11:39:01 -04:00
Jesse Squires
5b27c16472 Update faq.md 2016-04-04 21:28:55 -07:00
Jesse Squires
34d37e3e59 attempt to fix travis. 2016-04-04 18:08:10 -07:00
Jesse Squires
5a5614c3b9 attempt to fix travis. 2016-04-04 17:46:57 -07:00
eliburke
3dabbbf1f2 fixed typo in author's name 2016-04-04 17:18:25 -07:00
Jesse Squires
c938362d7c Update README.md 2016-04-04 09:42:27 -07:00
Jesse Squires
932e61d0f1 Update contributor_onboarding.md 2016-04-04 09:40:30 -07:00
Jesse Squires
028860b5cd xcode 7.3 and pod update 2016-04-04 09:26:20 -07:00
Jesse Squires
17b848c152 Update ISSUE_TEMPLATE.md 2016-04-02 13:52:45 -07:00
Jesse Squires
39dc4e46de Update PULL_REQUEST_TEMPLATE.md 2016-04-02 13:51:06 -07:00
Jesse Squires
8b95f41c55 Update ISSUE_TEMPLATE.md 2016-03-23 09:07:41 -07:00
Jesse Squires
f72235a2bf Update ISSUE_TEMPLATE.md 2016-03-07 07:21:19 -08:00
Jesse Squires
bc7bef4c99 Update PULL_REQUEST_TEMPLATE.md 2016-03-07 07:19:35 -08:00
Jesse Squires
299dd01b54 Update ISSUE_TEMPLATE.md 2016-03-07 07:06:07 -08:00
Jesse Squires
b537f708d6 Update ISSUE_TEMPLATE.md 2016-03-06 20:16:10 -08:00
Jesse Squires
c1641d68bf Update ISSUE_TEMPLATE.md 2016-03-06 20:12:48 -08:00
Jesse Squires
444283922d Merge pull request #1485 from KennyWZhang/develop
fix a typo of JSQMessagesTimestampFormatterTests.m
2016-03-06 19:48:31 -08:00
Kenny.W.Zhang
637d4e1c40 1. fix a typo of JSQMessagesTimestampFormatterTests.m
2. remove one line unused code of JSQMessagesViewController.m
2016-03-07 10:03:19 +08:00
Jesse Squires
cd0c9f61ed Merge pull request #1477 from GuyKahlon/BugFix#1449
fix for preferredDefaultHeight. close #1449
2016-03-03 23:14:22 +09:00
Guy Kahlon
4b9a5ff5ad Bug #1449 - It doesn't seem like you can change the height of the inputToolbar using the documented property preferredDefaultHeight since it is used to configure the height constraint in viewDidLoad.
In order to fix the bug I added the line of code:

self.toolbarHeightConstraint.constant = self.inputToolbar.preferredDefaultHeight;

In the method:

viewWillAppear, and now the view load with the correct constraints.
2016-03-03 15:39:07 +02:00
Jesse Squires
d616d11809 clean up 2016-02-23 07:06:53 -08:00
Jesse Squires
e5979c1ca4 Merge pull request #1460 from mauruskuehne/issue_1142_designated_initializers
marked designated initializers (close issue #1142)
2016-02-23 07:05:45 -08:00
Jesse Squires
59d04621c3 Update contributor_onboarding.md 2016-02-23 06:59:10 -08:00
Maurus Kühne
6b54c75bc9 marked designated initializers where applicable (issue #1142) 2016-02-22 18:23:46 +01:00
Jesse Squires
72e91ffbd2 Merge pull request #1459 from mauruskuehne/onboarding_guide_typos
fixed typos in the onboarding guide
2016-02-22 09:04:34 -08:00
Maurus Kühne
93c4de3ec4 fixed typos in the onboarding guide 2016-02-22 17:52:55 +01:00
Jesse Squires
fe251ef91c Update README.md 2016-02-21 17:57:26 -08:00
Jesse Squires
d922149efe Update contributor_onboarding.md 2016-02-21 17:48:26 -08:00
Jesse Squires
7c248fdb4f Update contributor_onboarding.md 2016-02-21 17:46:45 -08:00
Jesse Squires
13824b2264 Update contributor_onboarding.md 2016-02-21 17:18:39 -08:00
Jesse Squires
d16852af96 Update contributor_onboarding.md 2016-02-21 17:05:33 -08:00
Jesse Squires
aaa6fefc41 Update contributor_onboarding.md 2016-02-21 17:03:44 -08:00
Jesse Squires
51beebb07f Update contributor_onboarding.md 2016-02-21 16:52:35 -08:00
Jesse Squires
a9d34e8da1 Update contributor_onboarding.md 2016-02-21 09:06:35 -08:00
Jesse Squires
3dd0bab1dc Update contributor_onboarding.md 2016-02-21 08:56:28 -08:00
Jesse Squires
31ba236883 Update contributor_onboarding.md 2016-02-21 08:38:44 -08:00
Jesse Squires
f3ad9887bf Update CONTRIBUTING.md 2016-02-20 14:28:03 -08:00
Jesse Squires
403745cbd3 Create CONDUCT.md 2016-02-20 14:25:38 -08:00
Jesse Squires
ad7c3b8f99 Update PULL_REQUEST_TEMPLATE.md 2016-02-20 10:15:44 -08:00
Jesse Squires
3464c63f69 Update CONTRIBUTING.md 2016-02-20 10:14:35 -08:00
Jesse Squires
0a4a628c76 Create PULL_REQUEST_TEMPLATE.md 2016-02-20 10:07:14 -08:00
Jesse Squires
2a60b406a6 Update ISSUE_TEMPLATE.md 2016-02-20 09:51:56 -08:00
Jesse Squires
b9999066a9 Update ISSUE_TEMPLATE.md 2016-02-20 09:51:00 -08:00
Jesse Squires
9c1efe10a9 Update ISSUE_TEMPLATE.md 2016-02-20 09:44:38 -08:00
Jesse Squires
7c4b4f4639 Create ISSUE_TEMPLATE.md 2016-02-20 09:34:04 -08:00
Jesse Squires
3d9bb6d6a4 Update README.md 2016-02-20 09:14:45 -08:00
Jesse Squires
685ef7019e Update README.md 2016-02-20 09:10:51 -08:00
Jesse Squires
0f6095fc5b Update README.md 2016-02-20 09:09:27 -08:00
Jesse Squires
a9721495d4 Update CONTRIBUTING.md 2016-02-20 09:08:02 -08:00
Jesse Squires
01edde38e7 Update contributor_onboarding.md 2016-02-19 08:28:43 -08:00
Jesse Squires
b461d5a3b3 Update contributor_onboarding.md 2016-02-19 08:27:11 -08:00
Jesse Squires
0c8b939406 Create contributor_onboarding.md 2016-02-19 08:16:44 -08:00
Jesse Squires
0c33d88198 Update getting_started.md 2016-02-19 07:58:06 -08:00
Jesse Squires
6621f6b584 break out getting started guide 2016-02-19 07:57:40 -08:00
Jesse Squires
a29cbb7c79 capitalize docs directory for consistency 2016-02-19 07:53:47 -08:00
Jesse Squires
f5f2e67e5b capitalize docs directory for consistency 2016-02-19 07:53:28 -08:00
Jesse Squires
03473dfe0a capitalize docs directory for consistency 2016-02-19 07:52:33 -08:00
Jesse Squires
2f33e3c9cd Update CONTRIBUTING.md 2016-02-19 07:50:10 -08:00
Jesse Squires
b49a69a487 Update CONTRIBUTING.md 2016-02-19 07:48:06 -08:00
Jesse Squires
ec601a6c62 Update README.md 2016-02-19 07:47:13 -08:00
Jesse Squires
be5dc2764c Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2016-02-19 07:44:29 -08:00
Jesse Squires
1f97141421 move contributing.md to new .github/ dir #1453 2016-02-19 07:44:02 -08:00
Jesse Squires
6dda0b041a Update README.md 2016-02-18 21:56:40 -08:00
Jesse Squires
239f5e6fe8 Update README.md 2016-02-14 20:50:19 -08:00
Jesse Squires
c296dac954 Merge branch 'develop' into release_8.0 2016-02-11 18:39:31 -08:00
Jesse Squires
69b5779f6b Merge pull request #1203 from sebastianludwig/flexible_is_outgoing
Customizable isOutgoing
2016-02-10 17:53:53 -08:00
Sebastian Ludwig
5d5551b913 Extracted logic to determine if a message is outgoing into method to be able to specialize it in subclasses. 2016-02-10 11:37:21 -06:00
Jesse Squires
90471f36a5 Merge pull request #1436 from mauruskuehne/issue_1433_cleanup_documentation
Clean up repo documentation (closes #1433)
2016-02-08 17:27:25 -08:00
Maurus Kühne
2c1210c892 closes #1433
- moved the documentation to a separate directory
- updated links in README.md
2016-02-08 17:41:04 +01:00
Jesse Squires
932b7da2d9 Merge branch 'develop' into release_8.0 2016-02-07 22:06:21 -08:00
Jesse Squires
776c94c264 Update README.md 2016-02-05 23:29:27 -08:00
Jesse Squires
7f7b850890 fix proj settings 2016-02-05 23:20:42 -08:00
Jesse Squires
e65c34ac78 Update README.md 2016-02-05 23:11:25 -08:00
Jesse Squires
b846d4b4a3 Create CHANGELOG.md
#1386
2016-02-05 23:08:12 -08:00
Jesse Squires
2891d192f4 Update README.md 2016-02-05 23:05:48 -08:00
Jesse Squires
04e0a43eb4 require super. close #1406 2016-02-05 22:57:43 -08:00
Jesse Squires
69e38bcbad pod update 2016-02-05 22:22:38 -08:00
Jesse Squires
11af29dcbb Merge pull request #1415 from 2-4601/finnish-him
Add Finnish localisation
2016-01-26 17:45:53 -08:00
2-4601
54fff888f2 Add Finnish localisation 2016-01-26 18:31:48 +02:00
Jesse Squires
70c3498c46 Merge pull request #1395 from wzs/develop
Fix typo in appledoc tag name
2016-01-15 08:53:54 -08:00
Paweł Wrzosek
911b115768 Fix typo in appledoc tag name
Prevents from "Unknown command tag name 'disscussion'; did you mean 'discussion'?" warning
2016-01-15 14:54:07 +01:00
Jesse Squires
d7e2748f3e Update README.md 2016-01-14 17:49:46 -08:00
Jesse Squires
7b6a6863bf Merge pull request #1391 from rashoodkhan/patch-1
Added Yellow Partner to the apps using list
2016-01-13 14:51:04 -08:00
Rashid Khan
ca70936656 Update apps_using_this_library.md 2016-01-13 16:58:30 -03:00
Jesse Squires
5b529462fb Update FAQ.md 2016-01-12 08:19:58 -08:00
Jesse Squires
9a9e28b35c Update FAQ.md 2016-01-12 08:07:06 -08:00
Jesse Squires
f693689ca6 Merge branch 'develop' into release_8.0 2016-01-11 22:15:32 -08:00
Jesse Squires
5bcd72ffce merge. fuck you xcode 2016-01-11 22:14:53 -08:00
Jesse Squires
a04482c1e8 wtf fuck you xcode 2016-01-11 22:14:28 -08:00
Jesse Squires
42aaff754b merge 2016-01-11 22:14:05 -08:00
Jesse Squires
2393ea6c16 wtf 2016-01-11 22:12:38 -08:00
Jesse Squires
6f90c0e93a remove OCMock and make everything not break. 2016-01-11 22:09:32 -08:00
Jesse Squires
807b5fe9ea clean up / modernize 2016-01-11 21:46:23 -08:00
Jesse Squires
4c52e50b51 Update FAQ.md 2016-01-09 18:47:29 -08:00
Jesse Squires
18703786e5 Update FAQ.md 2016-01-09 18:46:56 -08:00
Jesse Squires
c980b20292 Update FAQ.md 2016-01-09 18:44:05 -08:00
Jesse Squires
e935338e17 Update README.md 2016-01-09 18:37:40 -08:00
Jesse Squires
5d1ddb909a Create apps_using_this_library.md 2016-01-09 18:33:35 -08:00
Jesse Squires
0d19bb201d Update README.md 2016-01-09 18:26:16 -08:00
Jesse Squires
8e5f36593e Create MIGRATION.md 2016-01-09 18:21:16 -08:00
Jesse Squires
88f2a908c7 Create FAQ.md
close #1387
2016-01-09 18:12:04 -08:00
Jesse Squires
419a14210c Update README.md 2016-01-09 18:02:56 -08:00
Jesse Squires
75692259db Update README.md 2015-12-31 16:53:40 +01:00
Jesse Squires
59cd37a969 update travis. everything is horrible. 2015-12-06 18:36:15 -08:00
Jesse Squires
b99b2a3b38 update travis 2015-12-06 15:29:51 -08:00
Jesse Squires
506e82f9be update travis 2015-12-06 14:35:02 -08:00
Jesse Squires
2baed6f61d Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-12-06 14:13:18 -08:00
Jesse Squires
238ec1d13d Update README.md 2015-12-06 14:13:11 -08:00
Jesse Squires
a58d3e34d2 update travis 2015-12-06 14:11:03 -08:00
Jesse Squires
ea14a506e8 Update README.md 2015-12-06 14:03:33 -08:00
Jesse Squires
53f66cd8a4 Merge pull request #1300 from ReadmeCritic/develop
Update redirects in README
2015-12-06 14:00:50 -08:00
Jesse Squires
4a009760da update travis 2015-12-06 13:38:46 -08:00
Jesse Squires
820ad7c9b4 update travis 2015-12-06 13:21:39 -08:00
Jesse Squires
f50127ca4e Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-12-06 12:51:20 -08:00
Jesse Squires
7485f3d1d3 update travis 2015-12-06 12:51:15 -08:00
Jesse Squires
cc678456dc Update README.md 2015-12-06 12:46:52 -08:00
Jesse Squires
1803ffbd6c update travis 2015-12-06 12:41:04 -08:00
Jesse Squires
f29f2e284d update travis 2015-12-06 12:33:34 -08:00
Jesse Squires
8716568a4d update travis 2015-12-06 11:52:18 -08:00
Jesse Squires
f419972a89 fix action sheet in demo. close #1221 2015-12-06 11:21:27 -08:00
Jesse Squires
faf95defde Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-12-06 11:09:10 -08:00
Jesse Squires
ebc8e2f02c update travis 2015-12-06 11:08:16 -08:00
Jesse Squires
f82cb30939 Update .travis.yml 2015-11-26 09:41:51 -08:00
Jesse Squires
5a01def7fb update xibs 2015-11-12 21:09:18 -08:00
Jesse Squires
e0c53ac15b style cleanup 2015-11-12 20:32:43 -08:00
Jesse Squires
ef4f67d7d7 add vietnamese localization. close #1224 2015-11-12 20:30:28 -08:00
Jesse Squires
a00fa9dc52 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-11-12 20:25:04 -08:00
Jesse Squires
6ab06a44a8 Merge pull request #1238 from harlanhaskins/develop
Implemented adaptive UIViewController responses to invalidate message bubble cache on size change. Fix #1212.
2015-11-12 20:24:19 -08:00
Jesse Squires
027ed01416 update pods 2015-11-12 20:22:28 -08:00
Jesse Squires
88b0301449 update travis. close #1255. 2015-11-12 20:21:43 -08:00
Jesse Squires
155990c63b Update LICENSE 2015-11-06 22:27:40 -08:00
frankenbot
487e15a163 Update redirects 2015-11-04 19:24:14 -08:00
Jesse Squires
af61aa9335 Merge pull request #1292 from ThirakornP/patch-1
Add Thai Localization
2015-10-28 22:28:16 -07:00
Thriakorn
695f09f968 Add Thai Localization 2015-10-29 09:46:02 +07:00
Jesse Squires
0c5c2b6bfb Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-10-27 22:09:23 -07:00
Jesse Squires
123199aa6a pod update 2015-10-27 22:09:16 -07:00
Jesse Squires
3a49d81fdc Merge pull request #1258 from juliensaad/develop
[Localization] Update French version of Send button to match iOS version
2015-10-13 22:05:14 -07:00
juliensaad
36e5d25146 Update french version of Send button to match iOS version (envoi becomes envoyer) 2015-10-13 14:35:25 -04:00
Harlan Haskins
7917c423cc Implemented viewWillTransitionToSize:withTransitionCoordinator: and traitCollectionDidChange: for messages view controller to remove cached message bubble sizes on size class transition. This is necessary to support split-screen multitasking. 2015-10-02 15:32:10 -04:00
Jesse Squires
49135c660a Update README.md
update badges
2015-09-27 20:32:25 -07:00
Jesse Squires
553f5ecbb8 Update README.md 2015-09-19 13:38:10 -07:00
Jesse Squires
25a58853b2 Merge pull request #1208 from funkyV/develop
Update README.md
2015-09-18 21:43:25 -07:00
funkyV
9f64e6a25a Update README.md
added PimpMyCall to the apps that use JSQMessagesViewController.
2015-09-18 13:36:41 +03:00
Jesse Squires
8ba29137e8 png crush 2015-09-14 22:26:00 -07:00
Jesse Squires
ac25bd4f2f Merge pull request #1189 from walsh2000/fix_1174_again
Address #1174 & prevent inputToolbar-positioning regression
2015-09-14 22:20:11 -07:00
Jesse Squires
611ef2dab2 Merge pull request #1201 from harlanhaskins/develop
Updated screenshot with new location behavior
2015-09-14 21:57:34 -07:00
Harlan Haskins
1968ffcfa7 Updated screenshot with new location behavior. 2015-09-15 00:38:50 -04:00
Jesse Squires
f65b452b93 Update README.md 2015-09-13 21:24:34 -07:00
Jesse Squires
e72bfeed1f Update README.md 2015-09-13 21:10:03 -07:00
Jesse Squires
1e7ded798b update travis 2015-09-13 21:09:00 -07:00
Jesse Squires
12e3dc6442 Merge pull request #1199 from dmyers/patch-1
Removed old references to text and media messages
2015-09-13 10:48:57 -07:00
Derek Myers
a735dd3da5 Removed old references to text and media messages 2015-09-12 23:16:16 -05:00
Raymond Walsh
b95e606447 align code to repo code style
1. dot notation
2. rename ivar
2015-09-08 10:00:53 -07:00
Raymond Walsh
42d85c66d5 Address #1174 & prevent keyboard-positioning regression
Track the state of first-responder when the interactive pop gesture begins
Restore the first-responder state when pop gesture ends/cancels
2015-09-04 10:42:35 -07:00
Jesse Squires
e63f45308a oops. default to NO for fixed-width bubbles. 2015-09-03 21:34:56 -07:00
Jesse Squires
684aac33e7 version numbers 2015-09-03 21:15:23 -07:00
Jesse Squires
6648fe06f9 clean up and fixes from #1035 2015-09-03 21:12:11 -07:00
Jesse Squires
1d4be68944 Merge pull request #1035 from kohtenko/develop_toolbar_customization
Custom spacing for input toolbar items
2015-09-03 21:08:09 -07:00
Jesse Squires
0730fe5ebe comments and clean up from #1164 2015-09-03 21:02:44 -07:00
Jesse Squires
9ebbcb5d97 Merge pull request #1164 from walsh2000/textBubbleWidth_1112_dos
create a property to control Rotation-Independent bubble width. close #1112
2015-09-03 20:43:45 -07:00
Raymond Walsh
678d3348ed make the magix value configurable
resolves @jessesquires most recent comment/request
2015-09-03 09:28:13 -07:00
Jesse Squires
27ed04dae6 pod update 2015-09-02 23:40:18 -07:00
Jesse Squires
dad900b185 clean up / tweak demo changes from #1176 2015-09-02 23:27:01 -07:00
Jesse Squires
1d8ced57f4 Merge pull request #1176 from walsh2000/two_level_push
add a way to push our VC onto the 2nd level
2015-09-02 23:13:15 -07:00
Jesse Squires
e217043e06 fix Xcode's derpy warning because it's confused about the -initWithImage: selector. 2015-09-02 23:09:32 -07:00
Jesse Squires
875eab6a54 fix regression from #1175. must remove pop gesture in willDisappear. + clean up and formatting. 2015-09-02 23:08:19 -07:00
Jesse Squires
0317f7ff8c Merge pull request #1175 from walsh2000/fix_1174
Fix #1174
2015-09-02 23:00:49 -07:00
Jesse Squires
42d4d369e7 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-09-02 22:58:37 -07:00
Jesse Squires
07cccf00ee Update .travis.yml 2015-08-27 20:50:13 -07:00
Jesse Squires
031de6dd0a Update .travis.yml 2015-08-27 20:26:36 -07:00
Raymond Walsh
cd46b83b69 Merge remote-tracking branch 'upstream/develop' into fix_1174 2015-08-25 08:48:21 -07:00
Jesse Squires
9042e961b0 switch from xctool to xcodebuild. THANKS TRAVIS 2015-08-24 21:10:36 -07:00
Raymond Walsh
375439060b user accessor instead of direct ivar access 2015-08-24 20:15:30 -07:00
Raymond Walsh
f38934e03d add a way to push our VC onto the 2nd level
I found this was necessary for testing the fix for #1174 & #257, so I thought it might be a handy feature to have in the demo app
2015-08-24 14:33:41 -07:00
Raymond Walsh
052dfdcdd9 Fix for issue 1174
This avoids the problems mentioned in #1174 by removing our target on the Interactive Pop Gesture at viewDidDisappear-time
It avoid regressing to the problems documented in #257 by capturing the UIGestureRecognizer (as weak) at the time we addTarget. This allow us to remember on whom we should removeTarget.

I will have a separate commit to add a 2-level navigation-controller push to the Demo project, but that is not directly related to #1174 nor #257
2015-08-24 14:31:10 -07:00
Jesse Squires
165adaef06 attempt to improve #747 2015-08-17 20:18:19 -07:00
okohtenko
f5cdd957e9 small changes in comments and properties names 2015-08-17 11:48:39 +03:00
Jesse Squires
f8cbc84e0f fix #1161. use correct coordinates for pan gesture 2015-08-15 10:42:06 -07:00
Raymond Walsh
5291d8c5d1 variable naming preferences 2015-08-14 20:27:38 -07:00
Raymond Walsh
9fa0e40397 updated documentation for new selector signature 2015-08-14 19:58:13 -07:00
Raymond Walsh
3e14180439 refactored a selector name & missed a usage 2015-08-14 19:56:31 -07:00
Raymond Walsh
ba77b23076 stylistics & naming changes 2015-08-14 19:50:20 -07:00
Jesse Squires
5124c1247e Merge pull request #1162 from harlanhaskins/develop
Fixed pin image drawing in JSQLocationMediaItem.
2015-08-14 17:55:04 -07:00
Raymond Walsh
48dfb0ea03 create a property to control Rotation-Independent bubble width
The default behavior will be to use the old method (rotation-dependent bubble widths)
Relates to issue #1112
2015-08-14 14:10:51 -07:00
Harlan Haskins
f72c03cde3 Simplified offset logic. 2015-08-14 14:55:19 -04:00
Harlan Haskins
e0141a3d7c Fixed pin image drawing in JSQLocationMediaItem. 2015-08-14 10:24:01 -04:00
Jesse Squires
ddc20c96ee finish implementing delete: action for cells. close #970 2015-08-13 21:27:39 -07:00
Jesse Squires
a3652df8b6 Merge branch 'develop' into issue_970_deleteAction 2015-08-13 21:12:02 -07:00
Jesse Squires
d701cbff14 docs clean up 2015-08-13 21:10:22 -07:00
Jesse Squires
6405d7dad6 Merge pull request #1136 from bryx-inc/develop
Added ability to intercept -[UITextView paste:]
2015-08-13 21:05:14 -07:00
Harlan Haskins
12dd5b2744 Added 'of' 2015-08-13 09:27:04 -04:00
Harlan Haskins
5b0badf923 Made comments more consistent with the rest of the library. 2015-08-13 09:26:19 -04:00
Jesse Squires
cd17e0de51 fix #1081 2015-08-12 22:33:35 -07:00
Jesse Squires
6d7ceda2bd fix travis script 2015-08-12 22:16:57 -07:00
Jesse Squires
983fb5823d Implement new bubbleSizeCalculator. close #438 and #347. Changes will affect #1112 and #1113. 2015-08-12 21:36:17 -07:00
Jesse Squires
679ac60698 Merge pull request #1111 from snaggled/develop
Always set data from bubbleImageDataSource to avoid inconsistency.
2015-08-11 22:16:09 -07:00
Jesse Squires
49f5d7ec9d Arabic localization. close #1130 2015-08-11 22:09:43 -07:00
Jesse Squires
9752be93cf Merge pull request #1149 from harlanhaskins/develop
Added Korean localization from #237.
2015-08-09 20:02:21 -07:00
Harlan Haskins
9a89ba2d12 Added Korean localization from #237. 2015-08-09 19:09:08 -04:00
Jesse Squires
e6480b57ea formatting 2015-08-05 20:40:04 -07:00
Jesse Squires
b344f2dfa3 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-08-05 20:38:34 -07:00
Jesse Squires
933f0dfe6c Merge pull request #1141 from atlassian/develop
fix JSQMessage convenience inits to return self, not JSQMessage for subclassing
2015-08-05 20:38:26 -07:00
Jesse Squires
d5272c4283 unshare breakpoint 2015-08-05 20:37:24 -07:00
Marcus Kida
c07c12e26a fix JSQMessage convenience inits return JSQMessage instead of instancetype 2015-08-06 11:36:01 +10:00
Jesse Squires
ec2e0a9a39 Update README.md 2015-08-04 21:50:08 -07:00
Harlan Haskins
62385e451a Made changes as per @jessesquires's comments.
Updated the demo for the new naming.
2015-08-04 09:31:31 -04:00
Harlan Haskins
08ff2cb0cb Fixed infinite recursion with calling the -[JSQComposerTextView paste:] 2015-08-03 19:31:03 -04:00
Harlan Haskins
8dea72a056 Added comments to demo implementation. 2015-08-03 16:39:29 -04:00
Harlan Haskins
c5c7050d60 Added JSQComposerTextViewDelegate with an optional delegate method for intercepting pastes.
Added demo to demo app of pasting an image from the UIPasteboard.
2015-08-03 16:36:57 -04:00
Jesse Squires
3fad9a9548 Update CONTRIBUTING.md 2015-08-03 07:11:57 -07:00
Jesse Squires
da6136da26 Update README.md 2015-07-26 12:06:41 -07:00
Philip McMahon
3c964a4d83 A more succinct solution 2015-07-24 10:21:12 -06:00
Jesse Squires
586c9597c0 fix travis. grrr 2015-07-23 22:07:57 -07:00
Jesse Squires
c28d4bfd26 use travis-ci xcode6.4 2015-07-23 21:58:42 -07:00
Jesse Squires
a7335bc2c1 increase timeout for async test. because travis-ci is derpy. everything is broke and terrible. programming sucks. goddamit. 2015-07-23 21:55:03 -07:00
Jesse Squires
cbeb533a54 fix failing tests 2015-07-23 21:04:29 -07:00
Philip McMahon
c4749a7991 Having some messages with bubbles and some without results in all messages having bubbles 2015-07-23 14:55:29 -06:00
Jesse Squires
7b2b238153 pod update. fix xcode7 warnings. update tests. 2015-07-22 22:55:23 -07:00
Jesse Squires
676dc75c14 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-07-22 22:33:02 -07:00
Jesse Squires
1140cac96f Update CONTRIBUTING.md 2015-07-22 21:54:43 -07:00
Jesse Squires
91e74b0f7b Merge pull request #1053 from dvor/patch-1
Fixing typo in documentation
2015-06-25 07:18:34 -07:00
Dmytro Vorobiov
3898476714 Fixing typo in documentation 2015-06-25 16:05:36 +02:00
Jesse Squires
16ed8c1f88 Update README.md 2015-06-23 18:55:32 -07:00
Jesse Squires
efa3c2b365 pod update 2015-06-16 21:27:19 -07:00
okohtenko
8cd4b0be87 custom spacing for input toolbar 2015-06-16 14:34:12 +03:00
Jesse Squires
122983ddbb Merge pull request #1027 from sebastianludwig/custom_action_fix
Fix #1026
2015-06-10 23:41:58 -07:00
Sebastian Ludwig
2870560006 Fixed #1026 by avoiding overreleasing the sender (the tapped message view cell) of a custom context menu action. 2015-06-10 20:43:56 +02:00
Jesse Squires
a2f8b39891 Merge pull request #1025 from rafaelatr3/develop
Adding missing 's' on the portuguese version of JSQMessages.strings
2015-06-09 18:07:54 -07:00
Rafael Rocha
b656f8adf9 Adding missing 's' on the portuguese version of JSQMessages.strings 2015-06-09 18:07:05 -03:00
Jesse Squires
867115b03c update spec 2015-05-31 11:24:29 -07:00
Jesse Squires
c2651dd0a4 pod update 2015-05-31 11:20:33 -07:00
Jesse Squires
ec8dcf66d5 Update LICENSE 2015-05-31 11:18:33 -07:00
Jesse Squires
acbb692b3d Update README.md 2015-05-31 11:18:17 -07:00
Jesse Squires
7606339770 pod update 2015-05-26 19:45:13 -07:00
Jesse Squires
9551159a20 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-05-26 19:39:24 -07:00
Jesse Squires
c8831f0b30 update ignore. include Pods/ 2015-05-26 19:39:11 -07:00
Jesse Squires
566ddb3301 Merge pull request #996 from sumihiro/localization_ja
Add Japanese Localization
2015-05-21 22:13:33 -07:00
sumihiro
ea373b0130 Add Japanese Localization 2015-05-22 09:52:58 +09:00
Jesse Squires
9859d3ab52 issue #970 WIP 2015-05-12 19:07:35 -07:00
Jesse Squires
8e8f0998be clean up and refinements for PR #950 and #756. issue #323. move maximumInputToolbarHeight to toolbar class. 2015-05-12 18:32:05 -07:00
Jesse Squires
27ec773edc Merge pull request #950 from werediver/develop-lbanders-extra
bug fix follow-up on issue #323
2015-05-12 18:05:24 -07:00
Jesse Squires
34f046c452 Merge pull request #756 from lbanders/develop
Add a maxToolbarHeight property to. fix #323
2015-05-12 18:00:58 -07:00
Jesse Squires
7e7edbf675 pod update 2015-05-11 18:06:19 -07:00
Jesse Squires
98368fc105 Merge pull request #973 from RQEBMM/issue_971_makeKeyboardControllerPublic
made keyboardController a public property. close #971
2015-05-07 11:43:56 -07:00
Benjamin McCloskey
08567a4be6 made keyboardController a public property 2015-05-07 12:52:07 -05:00
Jesse Squires
78c46c0ac4 Merge pull request #972 from vani2/bazar_app_link
Add link to Bazar app
2015-05-07 09:47:38 -07:00
Ivan Vavilov
2f94744368 Add link to Bazar app 2015-05-07 10:26:00 +03:00
Jesse Squires
ad761def43 more refinements from PR #811 2015-05-06 10:19:37 -07:00
Jesse Squires
c5c9c20246 clean up and refinements from PR #811 2015-05-06 10:05:09 -07:00
Jesse Squires
c4d38a8407 Merge pull request #811 from sebastianludwig/develop
Implemented #810: An easier way to handle custom menu actions. close #810
2015-05-06 09:27:10 -07:00
Jesse Squires
9db018bfce clear cached media views. close #754 2015-05-06 09:18:26 -07:00
Jesse Squires
0db2ab9e74 pod update 2015-05-05 16:48:32 -07:00
Jesse Squires
6a5aeb5ffb Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-05-05 14:46:03 -07:00
Jesse Squires
74acd93417 bump version nums 2015-05-05 14:45:54 -07:00
Jesse Squires
3247b45b13 Update README.md 2015-05-04 21:38:04 -07:00
Jesse Squires
bccad24efc Merge pull request #951 from tobiasoleary/remove_context_state_save_restore
Remove unneeded CGContext Save and Restore calls.
2015-05-04 16:17:48 -07:00
Tobias O'Leary
5e9e368f4d Remove unneeded CGContext Save and Restore calls.
In the private class methods of JSQMessagesAvatarImageFactory
(jsq_imageWitInitials, jsq_circularImage) there were calls to save and restore
the state of the graphic context.

The calls are not needed because UIGraphicsBeginImageContext creates a new
context in a default state.
2015-04-25 13:19:30 -04:00
Roman Fedoseyev
bff4ae7b86 #323 / #726 Possible crash caused by AutoLayout engine fault on iOS 7.x fixed.
The problem itself can be observed when the pull request #726 is applyed on top of v7.0.1+.
2015-04-25 16:13:17 +03:00
Jesse Squires
4c05c28f70 Update README.md 2015-04-24 08:59:35 -07:00
Jesse Squires
6b58a211c5 Merge pull request #938 from bearclough/issue_937_fix
Fix Issue #937: Updated implementation of UICollectionViewDelegate
2015-04-20 21:59:52 -07:00
bearclough
cb901cb026 Updated JSQMessagesViewController's implementation of UICollectionViewDelegate perform action for item to use the collectionView's dataSource instead of JSQMessagesViewController's 2015-04-20 21:10:18 -07:00
Jesse Squires
cd974aa015 suppress warning for now. fix in next release, see #920 2015-04-19 11:38:37 -07:00
Jesse Squires
a6a2884b07 bump version nums 2015-04-19 11:20:00 -07:00
Jesse Squires
a859a6862a fix toolbar button constraint issues. close #460 2015-04-19 11:03:47 -07:00
Jesse Squires
72e7343908 Merge pull request #888 from danhbear/issue_887_fix_springy_insert_sizezero
Don't return spring behavior for attributes with empty size. close #887
2015-04-19 10:46:39 -07:00
Jesse Squires
45590c3405 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-04-19 10:39:15 -07:00
Jesse Squires
cd085c683f Merge pull request #880 from erysaj/fix-toolbar-dragging
Fix toolbar dragging. close #666
2015-04-19 10:39:10 -07:00
Jesse Squires
853a3fe1c5 pod update 2015-04-19 10:30:22 -07:00
Daniel Bear
7610526965 PR style feedback
https://github.com/jessesquires/JSQMessagesViewController/pull/888/files#r28034689
2015-04-10 08:17:06 -07:00
Jesse Squires
ab831aaf67 fix demo contraints 2015-04-08 21:21:09 -07:00
Jesse Squires
5c57cee47f Merge pull request #889 from erysaj/fix-segfault-crashes
Fix segfault crashes
2015-04-08 21:14:56 -07:00
Jesse Squires
dcebef9d1e Merge pull request #915 from luosheng/develop
Revert @import for #import.
2015-04-08 21:08:22 -07:00
Luo Sheng
547cec7287 Revert @import for #import. 2015-04-09 11:51:31 +08:00
Eugene Rysaj
72540e2553 Nullify delegates to prevent crashes 2015-03-30 14:04:02 +03:00
Daniel Bear
1c5811107c Don't return spring behavior for attributes with empty size.
The demo project currently displays a new outgoing message using JSQMessagesViewController -finishSendingMessageAnimated:, which calls UICollectionView -reloadData. This works fine. However when new items are instead added using UICollectionView -insertItemsAtIndexPaths:, a failure occurs in the flow layout when trying to add the spring behavior to the UIDynamicAnimator in -prepareForCollectionViewUpdates:. This change protects against that failure, which is caused by an invalid zero size in the layout attributes. Adding a nil behavior instead behaves correctly.
2015-03-27 15:15:12 -07:00
Jesse Squires
ea42262a9a Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-03-26 21:41:51 -07:00
Jesse Squires
483f36402a pod update 2015-03-26 21:41:45 -07:00
Eugene Rysaj
7edc1312d1 fix detecting pre-iOS8 devices (did not work on iOS 8.0) 2015-03-24 15:15:08 +02:00
Eugene Rysaj
6086d26bc8 fix toolbar going out of sight when slowly dragging down and back in landscape orientation (iOS 7.x) 2015-03-24 15:00:19 +02:00
Leif Bredgaard Honore
e75c2fb166 Merge errors fixed 2015-03-22 10:55:13 +04:00
Leif Bredgaard Honore
0ed53ae8c5 Merge remote-tracking branch 'jessesquires/develop' into develop
Conflicts:
	JSQMessagesViewController/Controllers/JSQMessagesViewController.m
2015-03-22 08:12:56 +04:00
Jesse Squires
fb7119d3b2 Update README.md 2015-03-21 11:36:06 -07:00
Jesse Squires
71a7f519fc Update README.md 2015-03-21 11:34:13 -07:00
Jesse Squires
62c6844ce6 Update README.md 2015-03-20 21:53:38 -07:00
Leif Bredgaard Honore
dd0e214d13 #323 updated according to comments by @jessesquires - Also tests is now included 2015-03-19 10:39:31 +04:00
Jesse Squires
25a887a31e Merge pull request #867 from jeffreyjackson/patch-1
Update README.md
2015-03-17 14:40:47 -07:00
Jeffrey Jackson
bd82c11af6 Update README.md 2015-03-17 16:21:42 -04:00
Jesse Squires
3e69f1fc1d clean up from PR #841 2015-03-16 20:06:53 -07:00
Jesse Squires
acb047f25d Merge pull request #841 from jardamach/develop
Keyboard scrolling problem & fix of toolbar position while panning. fix #666. fix #405.
2015-03-16 20:06:01 -07:00
Jesse Squires
fc581c8b0b update and refine spec and resource loading. 2015-03-16 19:29:53 -07:00
Jesse Squires
007a945959 improve scrolling performance on iOS 8. #492 2015-03-16 18:37:23 -07:00
Jesse Squires
56f8a9c648 update spec. bump version numbers. 2015-03-16 18:27:48 -07:00
Jesse Squires
0f5cd6c2fd move strings to bundle. add bundle helper methods. #784 2015-03-16 18:19:29 -07:00
Jesse Squires
86746bd9d6 refine strings and keys 2015-03-16 17:13:31 -07:00
Jesse Squires
94b19ccb08 fix broken tests. derp. 2015-03-16 16:11:38 -07:00
Jesse Squires
88d2fe4ef4 update travis script 2015-03-16 15:34:17 -07:00
Jesse Squires
97bfef24c9 remove UIScrollViewKeyboardDismissModeInteractive. ref #666 2015-03-16 15:16:16 -07:00
Jesse Squires
f09dc0230e another fix for #684 2015-03-16 15:10:17 -07:00
Jesse Squires
a30f9bdee9 rename hash protocol method names in JSQMessageData and JSQMessageMediaData. fixes swift compatibility and core data issues. close #684 2015-03-16 15:07:56 -07:00
Jesse Squires
e23a248797 Fix #818 2015-03-16 14:56:58 -07:00
Jesse Squires
05c97700a2 don't upperCase string for avatarImageWithUserInitials. leave this up to the caller. close #755 2015-03-16 14:43:58 -07:00
Jesse Squires
1f64013617 Rename 'emptyCache' property on invalidationContext. close #661 2015-03-16 14:34:20 -07:00
Jesse Squires
a6437be1ab fix warnings from Xcode 6.3 beta 2015-03-16 14:26:50 -07:00
Jesse Squires
e0ae6cdb1f Update README.md 2015-03-06 18:05:46 -08:00
jardamach
d9aea32ed0 Keyboard scrolling problem & fix of toolbar position while panning #666 2015-03-06 13:59:04 +01:00
Jesse Squires
09db017b87 Update README.md 2015-03-02 12:02:59 -08:00
Jesse Squires
a180dcbee6 Update README.md 2015-02-26 21:45:47 -08:00
Jesse Squires
2698a699d8 Update README.md 2015-02-26 21:41:29 -08:00
Jesse Squires
0aa0ae2237 fix #791 2015-02-26 19:27:54 -08:00
Jesse Squires
1fb791f964 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-02-26 19:14:08 -08:00
Jesse Squires
0b8fb267d1 Fix #613 2015-02-26 19:13:53 -08:00
Sebastian Ludwig
b728ff3b4a Implemented #810: An easier way to handle custom menu actions. 2015-02-21 15:17:41 +07:00
Jesse Squires
fa7e42bfa5 Update README.md 2015-02-20 10:44:12 -08:00
Jesse Squires
82534ea75d update tests 2015-02-08 02:42:35 -08:00
Jesse Squires
08cc2d14d4 remove default values from senderDisplayName and senderId. add parameterAsserts instead. #774 2015-02-08 02:41:21 -08:00
Jesse Squires
720999efe9 oops. fix JSQMessagesCollectionViewCell. #773 2015-02-07 11:40:55 -08:00
Jesse Squires
0157f1a47e more fixes for cocoapods framework support. close #773 2015-02-07 11:36:49 -08:00
Jesse Squires
fc340cd166 fix spelling error. close #748 2015-02-05 22:42:27 -08:00
Jesse Squires
399544ff5d use CG geometry functions because goddammit. 2015-02-05 22:26:10 -08:00
Jesse Squires
245551f8ce revert changes from #702. causes other side effects. re-open #450. fuck keyboards. fuck this shitty keyboard API. and fuck iOS 8.1.3 goddammit. more beer please. 2015-02-05 22:25:37 -08:00
Jesse Squires
27d7a2e09c revert changes from PR #646, fix #706. PR #646 was possibly solved by #739. ref: #763 2015-02-05 21:57:48 -08:00
Jesse Squires
9e6e0f2524 refactor changes from #739 2015-02-05 21:48:32 -08:00
Jesse Squires
9893d4208f Merge pull request #739 from doggy/issue_#738_Fix
reset keyboard view status for pan gesture. close #738
2015-02-05 21:44:08 -08:00
Jesse Squires
3e80be42db refactor and clean up from PR #751 2015-02-05 21:19:15 -08:00
Jesse Squires
e354981b49 Merge pull request #751 from walsh2000/develop
Making JSQMessagesInputToolbar easier to subclass. Close #750
2015-02-05 21:04:52 -08:00
Jesse Squires
08377bc153 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-02-05 20:53:14 -08:00
Jesse Squires
1acb68119e close #702, fix #701, fix #450 2015-02-05 20:53:02 -08:00
Jesse Squires
f31b214c1b set header load button font 2015-02-05 20:41:58 -08:00
Jesse Squires
ddf11e62e4 Update README.md
add link to cocoapods. close #770
2015-02-05 09:23:40 -08:00
Leif Bredgaard Honore
fa668ef7da #323 fixed by adding a maxToolbarHeight property to JSQMessageViewController 2015-01-22 11:35:29 +04:00
Raymond Walsh
e3a2babfb2 move added code lower in the file
instead of adding it above awakeFromNib, place new functions near the bottom
2015-01-20 15:23:36 -08:00
Raymond Walsh
ed81bb2977 Modify JSQMessagesInputToolbar to make it easier to subclass
1. Toolbar instantiates the contentView through a method (which subclasses can override)
    2. JSQMessagesViewController gets default height from an accessor in JSQMessagesInputToolbar, instead of using a constant directly
2015-01-20 15:17:48 -08:00
doggy
6e7647d14a reset keyboard view status while the finger slide down to the outside of screen 2015-01-16 13:51:39 +08:00
Jesse Squires
99977d4938 bump version numbers 2015-01-10 16:02:10 -08:00
Jesse Squires
df26f3cc16 oops. fix use of iOS 8-only API. 2015-01-10 16:01:25 -08:00
Jesse Squires
1b9814ee5c bump version numbers 2015-01-10 15:33:22 -08:00
Jesse Squires
eec8ff4236 remove references to main bundle for cocoapods 0.36. close #698. 2015-01-10 15:22:22 -08:00
Jesse Squires
3779613da8 fix layout issues. close #722 2015-01-10 14:49:47 -08:00
Jesse Squires
f55bdad953 fix image copy, photo rotation issue. close #723 2015-01-10 14:41:49 -08:00
Jesse Squires
741f53f793 set cell default background color to clearColor. close #727 2015-01-10 14:39:28 -08:00
Jesse Squires
9bbdffa568 Merge branch 'develop' of https://github.com/jessesquires/JSQMessagesViewController into develop 2015-01-10 14:37:16 -08:00
Jesse Squires
db40c8b588 fix typing indicator rotation bug. close #712 2015-01-10 14:37:11 -08:00
Jesse Squires
dbad9a9325 update pods 2015-01-10 14:27:58 -08:00
Jesse Squires
5d21d699f6 Merge pull request #721 from ranunez/develop
Updated iOS version adoption statistics in README
2015-01-07 11:00:03 -08:00
Ricardo Nunez
b5ca3df47e Updated iOS version adoption statistics in README 2015-01-07 08:02:34 -08:00
Jesse Squires
191d2c3700 clean up 2014-12-24 14:35:10 -05:00
Jesse Squires
bbbb242521 Merge pull request #692 from asxasxasx/master
Limit input toolbar according to top inset
2014-12-24 14:29:40 -05:00
asxasxasx
174cae9b6c Limit input toolbar according to top inset
Limit input toolbar according to topContentAdditionalInset value. Fixed issue when textView expands under top view above collection view
2014-12-24 21:32:12 +06:00
Jesse Squires
7d6534eeae fix tests for travis-ci 2014-12-19 18:44:31 -05:00
202 changed files with 7377 additions and 1448 deletions

34
.codecov.yml Normal file
View File

@ -0,0 +1,34 @@
codecov:
branch: develop
coverage:
precision: 2
round: nearest
range: "60...100"
ignore:
- JSQMessagesDemo/*
- Pods/*
- JSQMessagesTests/*
status:
project:
default:
target: auto
threshold: 2.0
branches:
- master
- develop
patch:
default:
target: auto
branches:
- master
- develop
comment:
layout: "header, diff, changes, sunburst, uncovered"
branches:
- master
- develop
behavior: default

74
.github/CONDUCT.md vendored Normal file
View File

@ -0,0 +1,74 @@
# JSQMessagesViewController Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at **jesse.squires.developer [at] gmail [dot] com**. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

51
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,51 @@
# Contributing to JSQMessagesViewController
## Code of Conduct
Please read our [Code of Conduct](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONDUCT.md). Intolerance, disrespect, and any of form of negativity will not be tolerated.
## Opening a new issue
1. Read *all* of the [`README`](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md) :speak_no_evil:
* Search [open issues](https://github.com/jessesquires/JSQMessagesViewController/issues) *and* [closed issues](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+is%3Aclosed) to **avoid opening a duplicate issue!** :see_no_evil:
* If your issue exists, please comment on its thread with your new information :hear_no_evil:
* Otherwise, open a new issue with a good title and description :memo:
* Provide **all** of the following information:
- Library version(s) :octocat:
- iOS version(s) :iphone:
- Devices/Simulators affected :iphone:
- Expected behavior vs actual behavior
- Complete steps to reproduce the issue :warning:
- Link to a project that exhibits the issue, if possible fork the repo and modify the provided demo project :construction:
- Screenshots/GIFs/Videos showing the issue, if applicable :camera:
- Full crash log, if applicable :boom:
- Search for and list any issues that might be related :mag_right:
## Submitting a pull request
1. Link to the issue that the pull request resolves. If there isn't one, create one.
2. Write unit tests that test your changes, if applicable.
3. Update header docs, if needed.
4. Follow existing coding style, and these [style guidelines](https://github.com/jessesquires/HowToContribute#style-guidelines).
5. Resolve any merge conflicts.
6. Squash your commits into a single commit.
## Questions and help
See the [Questions & Help](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md#questions--help), and [Documentation](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md#documentation) sections in the `README`.
## General guidelines
Please also read through these more general [contribution guidelines](https://github.com/jessesquires/HowToContribute).
## Did you read all of this?
You even followed the links? Congratulations! You deserve a high-five. :tada:
![img](http://media.giphy.com/media/LdnaND03GRE9q/giphy.gif)
### New issue checklist
Now show me how awesome you are! :smile: When opening your new issue and filling out the checklist, you'll be asked for confirmation. Confirm that you've read this with these emoji: :muscle::sunglasses::facepunch:
> - [x] I have reviewed the contributing guidelines. Confirmation: :muscle::sunglasses::facepunch:

36
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,36 @@
## New issue checklist
<!-- Before submitting this issue, make sure you have done the following -->
- [ ] I have read all of the [`README`](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md), [documentation](http://cocoadocs.org/docsets/JSQMessagesViewController/), and [FAQ](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/faq.md).
- [ ] I have reviewed the [contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md). Confirmation: ____
- [ ] I have searched [existing issues](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+sort%3Acreated-desc) and **this is not a duplicate**.
### General information
- Library version(s):
- iOS version(s):
- Devices/Simulators affected:
- Reproducible in the demo project? (Yes/No):
- Related issues:
## Bug report
#### Expected behavior
> ...
#### Actual behavior
> ...
#### Steps to reproduce
> ...
#### Crash log? Screenshots? Videos? Sample project?
>...
## Question or Feature Request
> ...

11
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,11 @@
## Pull request checklist
- [ ] All tests pass. Demo project builds and runs.
- [ ] I have resolved any merge conflicts.
- [ ] I have followed the [coding style](https://github.com/jessesquires/HowToContribute#style-guidelines), and reviewed the [contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md). Confirmation: ____
#### This fixes issue #___.
## What's in this pull request?
>...

9
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Xcode
.DS_Store
# Xcode
/build/*
*/build/*
*.pbxuser
@ -18,8 +18,3 @@ DerivedData
.idea/
*.hmap
*.xccheckout
#CocoaPods
Pods

View File

@ -1,10 +1,44 @@
language: objective-c
osx_image: xcode7.3
before_install:
- export LANG=en_US.UTF-8
- gem install cocoapods
- brew update
- if brew outdated | grep -qx xctool; then brew upgrade xctool; fi
env:
global:
- LANG=en_US.UTF-8
- WORKSPACE="JSQMessages.xcworkspace"
- IOS_SCHEME="JSQMessages"
- IOS_SDK=iphonesimulator9.3
script:
- xctool clean build test -workspace JSQMessages.xcworkspace -scheme JSQMessages -sdk iphonesimulator7.1 ONLY_ACTIVE_ARCH=NO
matrix:
- DESTINATION="OS=8.1,name=iPhone 5" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" COVERAGE="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="YES" COVERAGE="YES"
before_install:
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
# skip pod install on travis-ci
# since we check-in the pods folder, etc. this isn't needed
install: true
script:
- if [ $POD_LINT == "YES" ]; then
pod spec lint;
pod lib lint;
fi
- if [ $RUN_TESTS == "YES" ]; then
xcodebuild clean build test -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO | xcpretty -c;
else
xcodebuild clean build -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO | xcpretty -c;
fi
# Build for reporting test coverage
- if [ $COVERAGE == "YES" ]; then
xcodebuild clean build test -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES;
fi
after_success:
- if [ $COVERAGE == "YES" ]; then
bash <(curl -s https://codecov.io/bash);
fi

125
CHANGELOG.md Normal file
View File

@ -0,0 +1,125 @@
# CHANGELOG
The changelog for `JSQMessagesViewController`. Also see the [releases](https://github.com/jessesquires/JSQMessagesViewController/releases) on GitHub.
--------------------------------------
7.3.4
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.3.4+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.3.4)
7.3.3
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.3.3+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.3.3)
7.3.2
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.3.2+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.3.2)
7.3.1
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.3.1+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.3.1)
7.3.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.3.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.3.0)
7.2.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.2.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.2.0)
7.1.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.1.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.1.0)
7.0.2
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.0.2+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.0.2)
7.0.1
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.0.1+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.0.1)
7.0.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A7.0.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.0.0)
6.1.3
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.1.3)
6.1.2
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A6.1.2+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.1.2)
6.1.1
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A6.1.1+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.1.1)
6.0.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A6.0.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.0.0)
5.3.0
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/5.3.0)
5.2.0
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/5.2.0)
5.1.0
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/5.1.0)
5.0.3
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/5.0.3)
5.0.0
-----
- [Milestone](https://github.com/jessesquires/JSQMessagesViewController/issues?q=milestone%3A5.0.0+is%3Aclosed)
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/5.0.0)
4.0.0
-----
- [GitHub release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/4.0.0)
All previous versions
---------------------
Unfortunately, release notes are not available for earlier versions of the library.

View File

@ -1,3 +0,0 @@
## How To Contribute
Please follow these sweet [contribution guidelines](https://github.com/jessesquires/HowToContribute).

View File

@ -0,0 +1,46 @@
# Apps using this library
These are the (known) apps that use `JSQMessagesViewController`. Submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare) to join the list! :smile:
-----------------
* [Hemoglobe](http://bit.ly/hemoglobeapp)
* [PocketSuite](https://itunes.apple.com/us/app/pocketsuite/id721795146)
* [FireChat](https://itunes.apple.com/us/app/firechat/id719829352)
* [Signal](https://github.com/WhisperSystems/Signal-iOS)
* [ClassDojo](https://itunes.apple.com/us/app/classdojo/id552602056)
* [Schools App](https://itunes.apple.com/us/app/schools-app/id495845755)
* [ChatSecure](https://chatsecure.org)
* [Bryx 911](https://itunes.apple.com/us/app/bryx-911/id813078029)
* [Kytt](https://itunes.apple.com/de/app/kytt-neue-leute-in-der-umgebung/id848959696)
* [Spark Social](https://itunes.apple.com/us/app/spark-social/id823785892)
* [Spabbit](https://itunes.apple.com/us/app/spabbit/id737363908)
* [Elodie](https://itunes.apple.com/app/elodie/id821610181)
* [Instaply](https://itunes.apple.com/us/app/instaply/id558562920)
* [Loopse](https://itunes.apple.com/us/app/loopse-spots-friends-sessions/id704783915)
* [Oxwall Messenger](https://github.com/tochman/OxwallMessenger)
* [FourChat](https://itunes.apple.com/us/app/fourchat/id650833730)
* [vCinity](https://itunes.apple.com/us/app/vcinity-chat-without-internet/id875395391)
* [Quick Text Message](https://itunes.apple.com/us/app/quick-text-message-fast-sms/id583729997)
* [Libraries for developers](https://itunes.apple.com/us/app/libraries-for-developers/id653427112)
* [Buhz|Hyve](https://itunes.apple.com/us/app/buhz-hyve/id818568956)
* [Ringring.io](https://github.com/ringring-io/ringring-ios)
* [gDecide](https://itunes.apple.com/ca/app/gdecide/id716801285)
* [AwesomeChat](https://github.com/relatedcode/RealtimeChat)
* [ParseChat](https://github.com/relatedcode/ParseChat)
* [Jib](http://jibapp.com)
* [Onvolo](https://itunes.apple.com/us/app/onvolo/id869332351)
* [EVCloudKitDao](https://github.com/evermeer/EVCloudKitDao)
* [Fluky Chat](https://itunes.apple.com/us/app/fluky-chat-secure-anonymous/id958605886)
* [VillageUnity](https://itunes.apple.com/us/app/village-unity/id919972368)
* [Pine](https://itunes.apple.com/us/app/pine-innovation-product-life/id946589228)
* [NotificationChat](https://github.com/relatedcode/EncryptedChat)
* [RealtimeChat](https://github.com/relatedcode/RealtimeChat)
* [Bazar](https://itunes.apple.com/ru/app/bazar-talk-about-everything/id885453058)
* [Roomie](https://itunes.apple.com/us/app/roomie-find-your-roomie/id962585201)
* [PimpMyCall](https://itunes.apple.com/us/app/pimp-my-call/id990167537)
* [Yellow Partner](https://itunes.apple.com/us/app/yellow-partner/id1062994361?ls=1&mt=8)
* [Radiate](https://itunes.apple.com/us/app/radiate/id939284774?mt=8)
* [Criptext](https://itunes.apple.com/us/app/criptext-secure-messenger/id848647361?mt=8)
* [multipeer-chat](https://github.com/J4awesome/multipeer-chat)
* *Your app here, submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare)!*

View File

@ -0,0 +1,130 @@
# Contributor Onboarding
*Contributor onboarding guide for JSQMessagesViewController*
This guide is intended to bring new core contributors up-to-speed on the project, organization, expectations, and best practices.
-------------------------
## Introduction
Welcome! :smile: If you are reading this, then you are (or are about to be) a core contributor! :tada: The goal of this document is to cover everything you need to know about helping to maintain this project. If you are not familiar with the code, the docs, the demo project, and everything else in the repo, then that should be your first step. Otherwise, continue on!
## Getting push access
Being a **contributor** means submitting pull requests, opening issues, etc. Being a **core contributor** means getting push access and other permissions.
We love freely giving push access to great contributors, and always err on trusting contributors with this responsibility. However, before granting you push access we would like to see a few things:
- An interest and dedication to the project
- Helping to triage issues, review pull requests, and diagnose bugs
- Submitting a couple great pull requests
We really prefer to grant push access to contributors who have a decent amount of time to share each week or month. If you cannot be extremely active on the project — that's ok! You can still be an :sparkles: awesome contributor :sparkles: without getting push access!
The rationale behind all of this is that we do not want to accumulate a *huge* list of **core contributors** that are *not* regularly active.
Remember, *your time* is *your time* — there is absolutely no pressure on you to spend a lot of time on this project, although it is greatly appreciated! :smile:
> **Note:** the rest of this document applies to both **contributors** and **core contributors**, but there are some details that would require having push access.
## Core team
### Project lead
Jesse Squires ([**@jessesquires**](https://github.com/jessesquires)) serves as the lead for `JSQMessagesViewController`.
Responsibilities include:
- Managing releases and CocoaPods distributions
- Merging code into `master`
- Overall guidance on design, architecture, and implementation
- Strategic direction for the library
- Onboarding new core contributors
- Everything under **Core Contributors** :smile:
- Anything not covered by **Core Contributors** :smile:
As core contributors grow and take on more repsonsibility, they can become a lead.
### Core contributors
Core contributors have push access and are responsible for:
- Bug fixes
- New features
- Triaging issues (managing, organizing)
- Reviewing pull requests
- Answering questions from the community on [issues](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=is%3Aissue+label%3A%22questions+%26+help%22+) and [StackOverflow](http://stackoverflow.com/questions/tagged/jsqmessagesviewcontroller)
- Documentation
Current core contributors:
- Harlan Haskans ([**@harlanhaskins**](https://github.com/harlanhaskins))
- Eli Burke ([**@eliburke**](https://github.com/eliburke))
## Pushing code
Although you have permissions to push code directly to `develop` as a core contributor, we ask that you *always* submit a pull request for code changes. After a code review and approval, you may merge your diff. For minor changes, like formatting or typos, pushing directly to `develop` is acceptable.
Always merge work to `develop` unless otherwise specified. The project lead will manage the `master` branch.
For now, Jesse ([**@jessesquires**](https://github.com/jessesquires)) should provide the final approval for *all* pull requests. However, as core contributors grow and establish themselves in the project, they can take on this responsibility as well.
## Project managment
### General guidelines
Above all, abide by our [code of conduct](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONDUCT.md) at all times. Be welcoming, kind, and inclusive.
Often, users do not follow our [contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md), fail to complete the [issue template](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/ISSUE_TEMPLATE.md), or fail to complete the [pull request template](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/PULL_REQUEST_TEMPLATE.md). This is frustrating, but the best response is to kindly remind and encourage them to follow the correct procedures next time.
When first responding to a newly opened issue or pull request, *always* thank the contributor and add some sweet emoji. Any positive emoji will work. (:+1:, :smile:, :sunglasses:, etc.) Choose your favorite.
> Thanks **@jessesquires**! :smile_cat:
Then continue on with the rest of your comment. There will be times where we simply cannot accept a patch for various reasons. In this case, kindly explain why it is not the right approach for the library, thank them for their time and effort, and encourage them to keep contributing.
In any situation, when in doubt, tag the project lead in a comment to get feedback.
### Development
- All work for minor and patch releases should happen on `develop`. For example, release 7.x.x.
- All work for major releases should happen on a release branch. For example, `release_8.0`.
- The project lead will manage the `master` branch.
For core contributors, always assign issues or pull requests to the appropriate team member. If you are working on an issue, assign it to yourself. If you would like someone to review a pull request, assign it to them.
### Managing issues
- Always add the appropriate label(s). There may be more than one.
- Assign to a release milestone, if applicable.
- Ask for more information from the user, if needed.
- Verify bugs. Leave comments on your findings as necessary.
- If it's a duplicate, label and close.
- Follow the general guidelines above.
##### Special labels
- [`needs review`](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+label%3A%22needs+review%22): These issues need to be triaged and confirmed. They are typically bugs or pull requests, but do not have to be. Once verified, `needs review` should be removed and any other appropriate labels should be added.
- [`new release roadmap`](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=is%3Aissue+label%3A%22new+release+roadmap%22+): For communicating new releases to the community.
- [`in-progress`](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+label%3Ain-progress): Specifies a task that is currently being worked on. Remove this label after closing a task.
- [`duplicate`](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=label%3Aduplicate+): For duplicate isses. When closing an issue as a duplicate be sure to leave a comment with the original issue number. *"Closing as duplicate of #6."*
- [`questions & help`](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+label%3A%22questions+%26+help%22): For community questions and help. Note that we are trying to refer questions to [StackOverflow](http://stackoverflow.com/questions/tagged/jsqmessagesviewcontroller) instead.
### Managing pull requests
- Review the code for correctness, performance, style, etc. Leave comments as needed.
- Always add the appropriate label(s). There may be more than one.
- Assign to a release milestone, if applicable.
- Follow the general guidelines above.
- If you think it's ready to go, tag the project lead to get the final :+1:
### Managing releases
All releases are organized using [milestones](https://github.com/jessesquires/JSQMessagesViewController/milestones). Use these to prioritize work and figure out what's next.
Issues and pull requests included in the next milestone release should be the highest priorty. Once a milestone is 100% complete, the project lead will merge `develop` or other release branches into `master`. The project lead will close the milestone, tag the release, and submit to CocoaPods.
### Managing documentation
Having high quality documentation and 100% coverage has a significant impact on the project's success.
Always add new docs for new public APIs and keep them up-to-date. Use existing docs and Apple's docs for Cocoa as guidelines for writing great documentation.

109
Documentation/faq.md Normal file
View File

@ -0,0 +1,109 @@
# FAQ
*Frequently asked questions for JSQMessagesViewController.*
Contributions are welcome! Please submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare).
------------------------------------
## For 7.x.x
#### Using `UITabBar` ?
Is the library compatible with `UITabBarController` and `UITabBar`? Yes and no. For the history on this issue, see [#179](https://github.com/jessesquires/JSQMessagesViewController/issues/179) and [#94](https://github.com/jessesquires/JSQMessagesViewController/issues/94). This seems to be the best workaround:
````objective-c
- (void)viewDidLoad
{
[super viewDidLoad];
self.edgesForExtendedLayout = UIRectEdgeNone;
}
````
#### *Springy bubbles?*
:warning: Note: this feature is still experimental.
````objective-c
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.collectionView.collectionViewLayout.springinessEnabled = YES;
}
````
#### *Remove avatars?*
````objective-c
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;
}
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
return nil;
}
````
#### *Need customize your collection view cells?*
There are 2 approaches to this, which one you choose depends on your needs.
1. Customize appearance and behavior of existing cells. (Easy)
2. Provide your own completely custom cell prototypes. (Hard)
> Also see [previous issues](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=custom+cell+in%3Atitle).
##### (1) Customizing existing cells
If you only need to make minor changes to the existing cells (colors, data detectors, etc.), then you simply need to override the following method. You have access to all properties on the cell. ([docs](http://cocoadocs.org/docsets/JSQMessagesViewController/7.2.0/Classes/JSQMessagesCollectionViewCell.html))
````objective-c
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
// Customize the shit out of this cell
// See the docs for JSQMessagesCollectionViewCell
return cell;
}
````
##### (2) Providing your own cell prototypes
This approach is more involved, but gives you greater flexibility. If you need to add or modify subviews of the cell, use this approach. ([docs](http://cocoadocs.org/docsets/JSQMessagesViewController/7.2.0/Classes/JSQMessagesViewController.html))
1. You need to provide your own cell subclasses, similar to the library's `JSQMessagesCollectionViewCell`, `JSQMessagesCollectionViewCellIncoming`, `JSQMessagesCollectionViewCellOutgoing`.
2. On your `JSQMessagesViewController` subclass, set the following properties according to your classes:
- `outgoingCellIdentifier`
- `outgoingMediaCellIdentifier`
- `incomingCellIdentifier`
- `incomingMediaCellIdentifier`
3. Register your cell classes/nibs with the collection view and the identifiers above
4. Override `-collectionView: cellForItemAtIndexPath:`. Do not call `super`. Since you are providing your own cells, calling `super` will perform a bunch of unnecessary work.
5. (Optional) For your model objects, implement `JSQMessageData` or subclass `JSQMessage` and extend to your needs.
#### *Customize your toolbar buttons?*
````objective-c
- (void)viewDidLoad
{
[super viewDidLoad];
// This button will call the `didPressAccessoryButton:` selector on your JSQMessagesViewController subclass
self.inputToolbar.contentView.leftBarButtonItem = /* custom button or nil to remove */
// This button will call the `didPressSendButton:` selector on your JSQMessagesViewController subclass
self.inputToolbar.contentView.rightBarButtonItem = /* custom button or nil to remove */
// Swap buttons, move send button to the LEFT side and the attachment button to the RIGHT
// For RTL language support
self.inputToolbar.contentView.leftBarButtonItem = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
self.inputToolbar.contentView.rightBarButtonItem = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
// The library will call the correct selector for each button, based on this value
self.inputToolbar.sendButtonOnRight = NO;
}
````

View File

@ -0,0 +1,56 @@
# Getting Started
*Getting started guide for JSQMessagesViewController*
-----------------------------
## For versions 6.x and 7.x
````objective-c
#import <JSQMessagesViewController/JSQMessages.h> // import all the things
````
* **Tutorials and blogs**
* Read the [blog post](http://www.jessesquires.com/introducing-jsqmessagesvc-6-0/) about the 6.0 release!
* Ray Wenderlich has a [great tutorial](http://www.raywenderlich.com/122148/firebase-tutorial-real-time-chat), written by [David East](https://twitter.com/_davideast). (For 7.x releases)
* **Demo Project**
* There's a sweet demo project: `JSQMessages.xcworkspace`.
* Run `pod install` first.
* Swift Example can be found in the SwiftExample folder just open the `SwiftExample.xcworkspace`.
* Run `pod install` first.
* [Firebase](https://www.firebase.com) also has a sweet [demo project](https://github.com/firebase/ios-swift-chat-example), and it's in Swift!
* **Message Model**
* Your message model objects should conform to the `JSQMessageData` protocol.
* However, you may use the provided `JSQMessage` class.
* **Media Attachment Model**
* Your media attachment model objects should conform to the `JSQMessageMediaData` protocol.
* However, you may use the provided classes: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`.
* Creating your own custom media items is easy! Simply follow the pattern used by the built-in media types.
* Also see `JSQMessagesMediaViewBubbleImageMasker` for masking your custom media views as message bubbles.
* **Avatar Model**
* Your avatar model objects should conform to the `JSQMessageAvatarImageDataSource` protocol.
* However, you may use the provided `JSQMessagesAvatarImage` class.
* Also see `JSQMessagesAvatarImageFactory` for easily generating custom avatars.
* **Message Bubble Model**
* Your message bubble model objects should conform to the `JSQMessageBubbleImageDataSource` protocol.
* However, you may use the provided `JSQMessagesBubbleImage` class.
* Also see `JSQMessagesBubbleImageFactory` and `UIImage+JSQMessages.h` for easily generating custom bubbles.
* **View Controller**
* Subclass `JSQMessagesViewController`.
* Implement the required methods in the `JSQMessagesCollectionViewDataSource` protocol.
* Implement the required methods in the `JSQMessagesCollectionViewDelegateFlowLayout` protocol.
* Set your `senderId` and `senderDisplayName`. These properties correspond to the methods found in `JSQMessageData` and determine which messages are incoming or outgoing.
* **Customizing**
* The demo project is well-commented. Please use this as a guide.
## Previous versions
Sorry! Guides are not available for older versions of the library.

View File

@ -0,0 +1,17 @@
# Migration Guide
*Migrating between major versions of JSQMessagesViewController?*
-----------------------------
## From `6.x` to `7.x`
See the [7.0 release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/7.0.0) for details about API changes.
## From `5.x` to `6.x`
See the [6.0 release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.0.0) for details about API changes.
## Previous versions
Unfortunately, versions prior to `5.0` outdate this document, and guides are not available.

View File

@ -7,8 +7,10 @@
objects = {
/* Begin PBXBuildFile section */
36CF33BD29CF36EB06D0CCFD /* libPods-JSQMessagesTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 782026E9E518622532ED474D /* libPods-JSQMessagesTests.a */; };
77CC17A895E6E12BC9CB549A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
54271E3B1C90469100294290 /* jsq_messages_sample.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 54271E3A1C90469100294290 /* jsq_messages_sample.m4a */; };
54271E3E1C905B9200294290 /* JSQAudioMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 54271E3D1C905B9200294290 /* JSQAudioMediaItem.m */; };
54271E401C905D1600294290 /* JSQAudioMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54271E3F1C905D1600294290 /* JSQAudioMediaItemTests.m */; };
544A32211CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 544A32201CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m */; };
88078A9D19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */; };
88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88324C3319F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m */; };
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */; };
@ -30,6 +32,8 @@
886C33FD19F4371E006B4997 /* JSQVideoMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 886C33FC19F4371E006B4997 /* JSQVideoMediaItem.m */; };
886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */; };
886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 886FFD2D19E9A65D00EB8485 /* UIDevice+JSQMessages.m */; };
8873B60C1AB7B244006DF9AC /* NSBundle+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 8873B60B1AB7B244006DF9AC /* NSBundle+JSQMessages.m */; };
8873B60E1AB7B63E006DF9AC /* JSQMessagesNSBundleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8873B60D1AB7B63E006DF9AC /* JSQMessagesNSBundleTests.m */; };
8885734A19DE540400E89D20 /* DemoSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8885734919DE540400E89D20 /* DemoSettingsViewController.m */; };
8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 8885734C19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m */; };
88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F2D19D8DF2500924534 /* AppDelegate.m */; };
@ -99,12 +103,14 @@
88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A2600019D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m */; };
88A2601B19D8E45600924534 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88A2601A19D8E45600924534 /* Info.plist */; };
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A901B519F618B100F99777 /* JSQMediaItem.m */; };
88B5C41F1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B5C41E1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.m */; };
88C00A4E1A44D4C600B004B3 /* JSQLocationMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */; };
88C00A501A44D4D800B004B3 /* JSQPhotoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */; };
88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */; };
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */; };
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8841B88719F4988800EA16B6 /* JSQMessages.strings */; };
94A4FA20C2FBD0D62614D5A8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
BF6DA766BD3B8893A67FB2BD /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C3F882AA48978C11F64DC2DF /* libPods.a */; };
C8994EF7DDBE74B9E3F1A16C /* libPods-JSQMessagesTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E23238C8D8DF79244DEE1787 /* libPods-JSQMessagesTests.a */; };
E8877F1947CE8050ECCD9539 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C3F882AA48978C11F64DC2DF /* libPods.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -118,30 +124,20 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0844AD596023C7658D39E241 /* Pods-JSQMessagesTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JSQMessagesTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JSQMessagesTests/Pods-JSQMessagesTests.release.xcconfig"; sourceTree = "<group>"; };
223FBACE0F24ADEF8B7F3F24 /* Pods-JSQMessagesTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JSQMessagesTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JSQMessagesTests/Pods-JSQMessagesTests.debug.xcconfig"; sourceTree = "<group>"; };
27B7FD1B722B36B26CB3460B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
782026E9E518622532ED474D /* libPods-JSQMessagesTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JSQMessagesTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
0B4D05069814EB50FB0F4229 /* Pods-JSQMessagesTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JSQMessagesTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JSQMessagesTests/Pods-JSQMessagesTests.release.xcconfig"; sourceTree = "<group>"; };
1D4D3B82D90888BCEAF890D3 /* Pods-JSQMessagesTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JSQMessagesTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JSQMessagesTests/Pods-JSQMessagesTests.debug.xcconfig"; sourceTree = "<group>"; };
3BA6237809BE0D008CFE3697 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
54271E3A1C90469100294290 /* jsq_messages_sample.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = jsq_messages_sample.m4a; sourceTree = "<group>"; };
54271E3C1C905B9200294290 /* JSQAudioMediaItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQAudioMediaItem.h; sourceTree = "<group>"; };
54271E3D1C905B9200294290 /* JSQAudioMediaItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQAudioMediaItem.m; sourceTree = "<group>"; };
54271E3F1C905D1600294290 /* JSQAudioMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQAudioMediaItemTests.m; sourceTree = "<group>"; };
544A321F1CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQAudioMediaViewAttributes.h; sourceTree = "<group>"; };
544A32201CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQAudioMediaViewAttributes.m; sourceTree = "<group>"; };
88078A9B19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaPlaceholderView.h; sourceTree = "<group>"; };
88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaPlaceholderView.m; sourceTree = "<group>"; };
88324C3319F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMaskerTests.m; sourceTree = "<group>"; };
883C11761A09FB100092A16D /* JSQMessagesCellTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCellTextView.h; sourceTree = "<group>"; };
883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCellTextView.m; sourceTree = "<group>"; };
8841B88619F4988800EA16B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88819F4988900EA16B6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88919F4988A00EA16B6 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88A19F4988B00EA16B6 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88B19F4988C00EA16B6 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/JSQMessages.strings"; sourceTree = "<group>"; };
8841B88C19F4988F00EA16B6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/JSQMessages.strings"; sourceTree = "<group>"; };
8841B88D19F4989000EA16B6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88E19F4989100EA16B6 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B88F19F4989200EA16B6 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89019F4989200EA16B6 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89119F4989300EA16B6 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89219F4989400EA16B6 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89319F4989500EA16B6 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89419F4989500EA16B6 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/JSQMessages.strings; sourceTree = "<group>"; };
8841B89519F4989600EA16B6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/JSQMessages.strings; sourceTree = "<group>"; };
88445B3019E0AE3F0014F889 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
88445B3219E0AE450014F889 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
88445B3419E0AE4A0014F889 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@ -157,6 +153,9 @@
886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = JSQMessagesViewController.podspec; sourceTree = "<group>"; };
886FFD2C19E9A65D00EB8485 /* UIDevice+JSQMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+JSQMessages.h"; sourceTree = "<group>"; };
886FFD2D19E9A65D00EB8485 /* UIDevice+JSQMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+JSQMessages.m"; sourceTree = "<group>"; };
8873B60A1AB7B244006DF9AC /* NSBundle+JSQMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+JSQMessages.h"; sourceTree = "<group>"; };
8873B60B1AB7B244006DF9AC /* NSBundle+JSQMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+JSQMessages.m"; sourceTree = "<group>"; };
8873B60D1AB7B63E006DF9AC /* JSQMessagesNSBundleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesNSBundleTests.m; sourceTree = "<group>"; };
8885734819DE540400E89D20 /* DemoSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoSettingsViewController.h; sourceTree = "<group>"; };
8885734919DE540400E89D20 /* DemoSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoSettingsViewController.m; sourceTree = "<group>"; };
8885734B19DE55D000E89D20 /* NSUserDefaults+DemoSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+DemoSettings.h"; sourceTree = "<group>"; };
@ -271,13 +270,17 @@
88A2601A19D8E45600924534 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
88A901B419F618B100F99777 /* JSQMediaItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMediaItem.h; sourceTree = "<group>"; };
88A901B519F618B100F99777 /* JSQMediaItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMediaItem.m; sourceTree = "<group>"; };
88B5C41D1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesBubblesSizeCalculator.h; sourceTree = "<group>"; };
88B5C41E1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesBubblesSizeCalculator.m; sourceTree = "<group>"; };
88B5C4201B7C424700EC79D4 /* JSQMessagesBubbleSizeCalculating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesBubbleSizeCalculating.h; sourceTree = "<group>"; };
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQLocationMediaItemTests.m; sourceTree = "<group>"; };
88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQPhotoMediaItemTests.m; sourceTree = "<group>"; };
88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQVideoMediaItemTests.m; sourceTree = "<group>"; };
88C4582E19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaViewBubbleImageMasker.h; sourceTree = "<group>"; };
88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMasker.m; sourceTree = "<group>"; };
97E6750B77E8A7042BA0754B /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
FC5C727E4CCDA2B95A7BA30C /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
AD6E75315517DE46FE495B65 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
C3F882AA48978C11F64DC2DF /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
E23238C8D8DF79244DEE1787 /* libPods-JSQMessagesTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JSQMessagesTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -291,7 +294,7 @@
88445B3519E0AE4A0014F889 /* CoreGraphics.framework in Frameworks */,
88445B3319E0AE450014F889 /* Foundation.framework in Frameworks */,
88445B3119E0AE3F0014F889 /* UIKit.framework in Frameworks */,
77CC17A895E6E12BC9CB549A /* libPods.a in Frameworks */,
E8877F1947CE8050ECCD9539 /* libPods.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -306,47 +309,39 @@
88445B3B19E0C0B10014F889 /* XCTest.framework in Frameworks */,
88445B3919E0C0AC0014F889 /* Foundation.framework in Frameworks */,
88445B3819E0C0A70014F889 /* UIKit.framework in Frameworks */,
94A4FA20C2FBD0D62614D5A8 /* libPods.a in Frameworks */,
36CF33BD29CF36EB06D0CCFD /* libPods-JSQMessagesTests.a in Frameworks */,
C8994EF7DDBE74B9E3F1A16C /* libPods-JSQMessagesTests.a in Frameworks */,
BF6DA766BD3B8893A67FB2BD /* libPods.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2BBEF3CD91C31A49E5FF9E3C /* Pods */ = {
isa = PBXGroup;
children = (
FC5C727E4CCDA2B95A7BA30C /* Pods.debug.xcconfig */,
27B7FD1B722B36B26CB3460B /* Pods.release.xcconfig */,
223FBACE0F24ADEF8B7F3F24 /* Pods-JSQMessagesTests.debug.xcconfig */,
0844AD596023C7658D39E241 /* Pods-JSQMessagesTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
636A8663AEEE5C37B65C515D /* Frameworks */ = {
isa = PBXGroup;
children = (
88445B4319E1B5110014F889 /* MapKit.framework */,
88445B4119E1B50B0014F889 /* CoreLocation.framework */,
88445B3419E0AE4A0014F889 /* CoreGraphics.framework */,
88445B4119E1B50B0014F889 /* CoreLocation.framework */,
88445B3219E0AE450014F889 /* Foundation.framework */,
782026E9E518622532ED474D /* libPods-JSQMessagesTests.a */,
97E6750B77E8A7042BA0754B /* libPods.a */,
88445B4319E1B5110014F889 /* MapKit.framework */,
88445B3619E0AE5C0014F889 /* QuartzCore.framework */,
88445B3019E0AE3F0014F889 /* UIKit.framework */,
88445B3A19E0C0B10014F889 /* XCTest.framework */,
C3F882AA48978C11F64DC2DF /* libPods.a */,
E23238C8D8DF79244DEE1787 /* libPods-JSQMessagesTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
8841B88219F4983C00EA16B6 /* Strings */ = {
842892590A65F355D8619D29 /* Pods */ = {
isa = PBXGroup;
children = (
8841B88719F4988800EA16B6 /* JSQMessages.strings */,
3BA6237809BE0D008CFE3697 /* Pods.debug.xcconfig */,
AD6E75315517DE46FE495B65 /* Pods.release.xcconfig */,
1D4D3B82D90888BCEAF890D3 /* Pods-JSQMessagesTests.debug.xcconfig */,
0B4D05069814EB50FB0F4229 /* Pods-JSQMessagesTests.release.xcconfig */,
);
path = Strings;
name = Pods;
sourceTree = "<group>";
};
88A25EF919D8DEC400924534 = {
@ -357,8 +352,8 @@
636A8663AEEE5C37B65C515D /* Frameworks */,
88A25F2B19D8DF2500924534 /* JSQMessagesDemo */,
88A25F1E19D8DEC500924534 /* JSQMessagesTests */,
2BBEF3CD91C31A49E5FF9E3C /* Pods */,
88A25F0319D8DEC400924534 /* Products */,
842892590A65F355D8619D29 /* Pods */,
);
sourceTree = "<group>";
};
@ -396,6 +391,7 @@
88A25F2B19D8DF2500924534 /* JSQMessagesDemo */ = {
isa = PBXGroup;
children = (
54271E3A1C90469100294290 /* jsq_messages_sample.m4a */,
88A25F2C19D8DF2500924534 /* AppDelegate.h */,
88A25F2D19D8DF2500924534 /* AppDelegate.m */,
88A25FD919D8E0C400924534 /* DemoMessagesViewController.h */,
@ -434,7 +430,6 @@
88A25F3F19D8E01A00924534 /* Assets */ = {
isa = PBXGroup;
children = (
8841B88219F4983C00EA16B6 /* Strings */,
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
);
path = Assets;
@ -445,6 +440,8 @@
children = (
88A25F5519D8E01A00924534 /* JSQSystemSoundPlayer+JSQMessages.h */,
88A25F5619D8E01A00924534 /* JSQSystemSoundPlayer+JSQMessages.m */,
8873B60A1AB7B244006DF9AC /* NSBundle+JSQMessages.h */,
8873B60B1AB7B244006DF9AC /* NSBundle+JSQMessages.m */,
88A25F5719D8E01A00924534 /* NSString+JSQMessages.h */,
88A25F5819D8E01A00924534 /* NSString+JSQMessages.m */,
88A25F5919D8E01A00924534 /* UIColor+JSQMessages.h */,
@ -491,6 +488,11 @@
88A25F6F19D8E01A00924534 /* Layout */ = {
isa = PBXGroup;
children = (
544A321F1CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.h */,
544A32201CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m */,
88B5C4201B7C424700EC79D4 /* JSQMessagesBubbleSizeCalculating.h */,
88B5C41D1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.h */,
88B5C41E1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.m */,
88A25F7019D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.h */,
88A25F7119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m */,
88A25F7219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h */,
@ -504,6 +506,8 @@
88A25F7619D8E01A00924534 /* Model */ = {
isa = PBXGroup;
children = (
54271E3C1C905B9200294290 /* JSQAudioMediaItem.h */,
54271E3D1C905B9200294290 /* JSQAudioMediaItem.m */,
88445B3E19E1B4470014F889 /* JSQLocationMediaItem.h */,
88445B3F19E1B4470014F889 /* JSQLocationMediaItem.m */,
88A901B419F618B100F99777 /* JSQMediaItem.h */,
@ -567,6 +571,7 @@
88A25FE219D8E18400924534 /* CategoryTests */ = {
isa = PBXGroup;
children = (
8873B60D1AB7B63E006DF9AC /* JSQMessagesNSBundleTests.m */,
88A25FE319D8E18400924534 /* JSQMessagesNSStringTests.m */,
88A25FE419D8E18400924534 /* JSQMessagesUIColorTests.m */,
88A25FE519D8E18400924534 /* JSQMessagesUIImageTests.m */,
@ -608,6 +613,7 @@
88A25FF219D8E18400924534 /* ModelTests */ = {
isa = PBXGroup;
children = (
54271E3F1C905D1600294290 /* JSQAudioMediaItemTests.m */,
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */,
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */,
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */,
@ -641,11 +647,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 88A25F2519D8DEC500924534 /* Build configuration list for PBXNativeTarget "JSQMessages" */;
buildPhases = (
3AF3068570D5C74873D84E30 /* Check Pods Manifest.lock */,
90945CFDCD14BCFE538D66C9 /* Check Pods Manifest.lock */,
88A25EFE19D8DEC400924534 /* Sources */,
88A25EFF19D8DEC400924534 /* Frameworks */,
88A25F0019D8DEC400924534 /* Resources */,
4CCCD7A86E86CB86C48E303C /* Copy Pods Resources */,
C8D68BB894C4DD38C5615198 /* Embed Pods Frameworks */,
908FA537E0B2FD4A94A60411 /* Copy Pods Resources */,
);
buildRules = (
);
@ -660,11 +667,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 88A25F2819D8DEC500924534 /* Build configuration list for PBXNativeTarget "JSQMessagesTests" */;
buildPhases = (
F4044DAC71D69462CA8CAE98 /* Check Pods Manifest.lock */,
95BD949B70ECF8FE9CDDB707 /* Check Pods Manifest.lock */,
88A25F1719D8DEC400924534 /* Sources */,
88A25F1819D8DEC400924534 /* Frameworks */,
88A25F1919D8DEC400924534 /* Resources */,
F6B484334A138916FC111868 /* Copy Pods Resources */,
78F522A7ECBD8D8774672696 /* Embed Pods Frameworks */,
B85CD3AA4EFCF4765BE7FAD9 /* Copy Pods Resources */,
);
buildRules = (
);
@ -682,7 +690,7 @@
88A25EFA19D8DEC400924534 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Hexed Bits";
TargetAttributes = {
88A25F0119D8DEC400924534 = {
@ -731,13 +739,13 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */,
886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */,
8861666D19F492B70025B958 /* JSQMessagesAssets.bundle in Resources */,
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
88A25FCD19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
88A25FD619D8E01A00924534 /* JSQMessagesToolbarContentView.xib in Resources */,
88A25F3A19D8DF2500924534 /* Images.xcassets in Resources */,
54271E3B1C90469100294290 /* jsq_messages_sample.m4a in Resources */,
88A25FBC19D8E01A00924534 /* JSQMessagesViewController.xib in Resources */,
88A25FD819D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */,
88A25F3919D8DF2500924534 /* Main.storyboard in Resources */,
@ -756,22 +764,22 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3AF3068570D5C74873D84E30 /* Check Pods Manifest.lock */ = {
78F522A7ECBD8D8774672696 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
4CCCD7A86E86CB86C48E303C /* Copy Pods Resources */ = {
908FA537E0B2FD4A94A60411 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -786,7 +794,7 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F4044DAC71D69462CA8CAE98 /* Check Pods Manifest.lock */ = {
90945CFDCD14BCFE538D66C9 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -801,7 +809,22 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
F6B484334A138916FC111868 /* Copy Pods Resources */ = {
95BD949B70ECF8FE9CDDB707 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
B85CD3AA4EFCF4765BE7FAD9 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -816,6 +839,21 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JSQMessagesTests/Pods-JSQMessagesTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
C8D68BB894C4DD38C5615198 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -829,6 +867,7 @@
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */,
88A25FBB19D8E01A00924534 /* JSQMessagesViewController.m in Sources */,
8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */,
544A32211CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m in Sources */,
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */,
88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */,
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */,
@ -849,7 +888,9 @@
88A25FE019D8E0C400924534 /* DemoModelData.m in Sources */,
88A25F3C19D8DF2500924534 /* main.m in Sources */,
88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */,
54271E3E1C905B9200294290 /* JSQAudioMediaItem.m in Sources */,
886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */,
88B5C41F1B7C422900EC79D4 /* JSQMessagesBubblesSizeCalculator.m in Sources */,
88A25FB619D8E01A00924534 /* NSString+JSQMessages.m in Sources */,
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */,
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */,
@ -863,6 +904,7 @@
88A25FE119D8E0C400924534 /* TableViewController.m in Sources */,
88A25FBD19D8E01A00924534 /* JSQMessagesAvatarImageFactory.m in Sources */,
88A25FB519D8E01A00924534 /* JSQSystemSoundPlayer+JSQMessages.m in Sources */,
8873B60C1AB7B244006DF9AC /* NSBundle+JSQMessages.m in Sources */,
88A25FD019D8E01A00924534 /* JSQMessagesComposerTextView.m in Sources */,
88A25FC319D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */,
);
@ -877,6 +919,7 @@
88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */,
88A2601519D8E18400924534 /* JSQMessagesInputToolbarTests.m in Sources */,
88A2601719D8E18400924534 /* JSQMessagesLoadEarlierHeaderViewTests.m in Sources */,
54271E401C905D1600294290 /* JSQAudioMediaItemTests.m in Sources */,
88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */,
88A2601619D8E18400924534 /* JSQMessagesLabelTests.m in Sources */,
88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */,
@ -896,6 +939,7 @@
88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */,
88A2600319D8E18400924534 /* JSQMessagesUIImageTests.m in Sources */,
88C00A4E1A44D4C600B004B3 /* JSQLocationMediaItemTests.m in Sources */,
8873B60E1AB7B63E006DF9AC /* JSQMessagesNSBundleTests.m in Sources */,
88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */,
88A2600619D8E18400924534 /* JSQMessagesViewControllerTests.m in Sources */,
88A2600519D8E18400924534 /* JSQMessagesKeyboardControllerTests.m in Sources */,
@ -914,28 +958,6 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
8841B88719F4988800EA16B6 /* JSQMessages.strings */ = {
isa = PBXVariantGroup;
children = (
8841B88619F4988800EA16B6 /* Base */,
8841B88819F4988900EA16B6 /* en */,
8841B88919F4988A00EA16B6 /* es */,
8841B88A19F4988B00EA16B6 /* de */,
8841B88B19F4988C00EA16B6 /* zh-Hans */,
8841B88C19F4988F00EA16B6 /* zh-Hant */,
8841B88D19F4989000EA16B6 /* ro */,
8841B88E19F4989100EA16B6 /* pl */,
8841B88F19F4989200EA16B6 /* ru */,
8841B89019F4989200EA16B6 /* pt */,
8841B89119F4989300EA16B6 /* fr */,
8841B89219F4989400EA16B6 /* it */,
8841B89319F4989500EA16B6 /* he */,
8841B89419F4989500EA16B6 /* nl */,
8841B89519F4989600EA16B6 /* tr */,
);
name = JSQMessages.strings;
sourceTree = "<group>";
};
88A25F3019D8DF2500924534 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
@ -967,6 +989,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1027,7 +1050,7 @@
};
88A25F2619D8DEC500924534 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FC5C727E4CCDA2B95A7BA30C /* Pods.debug.xcconfig */;
baseConfigurationReference = 3BA6237809BE0D008CFE3697 /* Pods.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@ -1038,6 +1061,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
@ -1045,7 +1069,7 @@
};
88A25F2719D8DEC500924534 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 27B7FD1B722B36B26CB3460B /* Pods.release.xcconfig */;
baseConfigurationReference = AD6E75315517DE46FE495B65 /* Pods.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@ -1056,6 +1080,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
@ -1063,20 +1088,18 @@
};
88A25F2919D8DEC500924534 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 223FBACE0F24ADEF8B7F3F24 /* Pods-JSQMessagesTests.debug.xcconfig */;
baseConfigurationReference = 1D4D3B82D90888BCEAF890D3 /* Pods-JSQMessagesTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = JSQMessagesTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSQMessages.app/JSQMessages";
};
@ -1084,16 +1107,14 @@
};
88A25F2A19D8DEC500924534 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0844AD596023C7658D39E241 /* Pods-JSQMessagesTests.release.xcconfig */;
baseConfigurationReference = 0B4D05069814EB50FB0F4229 /* Pods-JSQMessagesTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = JSQMessagesTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSQMessages.app/JSQMessages";
};

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0600"
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -14,7 +14,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F6B28C25B7B1259BD8C5B8B"
BlueprintIdentifier = "D14DE867BBE115B80620BD22C0E35F79"
BuildableName = "libPods.a"
BlueprintName = "Pods"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -51,10 +51,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
@ -76,17 +76,21 @@
ReferencedContainer = "container:JSQMessages.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "88A25F0119D8DEC400924534"
@ -99,12 +103,13 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "88A25F0119D8DEC400924534"

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="JRd-Be-psV">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="JRd-Be-psV">
<dependencies>
<deployment defaultVersion="1792" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
</dependencies>
<scenes>
<!--Root View Controller-->
@ -12,10 +12,11 @@
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="d0b-Sx-5kJ">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="CellIdentifier" textLabel="2qz-Z2-GmT" style="IBUITableViewCellStyleDefault" id="k8B-cw-dMU">
<rect key="frame" x="0.0" y="119" width="320" height="44"/>
<rect key="frame" x="0.0" y="114" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="k8B-cw-dMU" id="kX4-QF-oKx">
<rect key="frame" x="0.0" y="0.0" width="287" height="43"/>
@ -24,12 +25,15 @@
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2qz-Z2-GmT">
<rect key="frame" x="15" y="0.0" width="270" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
</tableViewCellContentView>
<animations/>
</tableViewCell>
</prototypes>
</tableView>
@ -51,17 +55,21 @@
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="GY5-ob-knb">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<sections>
<tableViewSection headerTitle="Messages" id="ygb-Dp-o4r">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Eii-ro-1yZ">
<rect key="frame" x="0.0" y="114" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Eii-ro-1yZ" id="qU9-o3-MWC">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="K7N-os-fuc">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="49" id="A6s-Sr-u8U"/>
<constraint firstAttribute="height" constant="31" id="z9i-uJ-MBq"/>
@ -72,29 +80,34 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Load extra messages" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bSS-CD-nfD">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstItem="bSS-CD-nfD" firstAttribute="top" secondItem="qU9-o3-MWC" secondAttribute="top" constant="10" id="4Iw-W0-qZs"/>
<constraint firstAttribute="trailing" secondItem="K7N-os-fuc" secondAttribute="trailing" constant="8" id="Fex-nr-C1R"/>
<constraint firstAttribute="bottom" secondItem="K7N-os-fuc" secondAttribute="bottom" constant="6" id="IBG-gn-Fpk"/>
<constraint firstItem="bSS-CD-nfD" firstAttribute="leading" secondItem="qU9-o3-MWC" secondAttribute="leading" constant="8" id="N5B-E5-Pzk"/>
<constraint firstItem="K7N-os-fuc" firstAttribute="leading" secondItem="bSS-CD-nfD" secondAttribute="trailing" constant="8" id="O2Y-G9-d6n"/>
<constraint firstItem="K7N-os-fuc" firstAttribute="top" secondItem="qU9-o3-MWC" secondAttribute="top" constant="6" id="UbM-aE-caS"/>
<constraint firstAttribute="centerY" secondItem="K7N-os-fuc" secondAttribute="centerY" id="j7N-59-vRk"/>
<constraint firstAttribute="bottom" secondItem="bSS-CD-nfD" secondAttribute="bottom" constant="9" id="poL-wE-Eir"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="bZI-G1-eYA">
<rect key="frame" x="0.0" y="158" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bZI-G1-eYA" id="1Ho-Zz-KN0">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hMq-Ee-EJK">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="height" constant="31" id="gM4-dK-cl7"/>
<constraint firstAttribute="width" constant="49" id="hvu-Yy-NTG"/>
@ -105,29 +118,34 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Load really long message" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YV3-GH-Yul">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstAttribute="centerY" secondItem="hMq-Ee-EJK" secondAttribute="centerY" id="CcO-KD-31y"/>
<constraint firstItem="hMq-Ee-EJK" firstAttribute="leading" secondItem="YV3-GH-Yul" secondAttribute="trailing" constant="8" id="KFO-nO-4r4"/>
<constraint firstItem="YV3-GH-Yul" firstAttribute="top" secondItem="1Ho-Zz-KN0" secondAttribute="top" constant="10" id="Lgl-fY-a8c"/>
<constraint firstAttribute="bottom" secondItem="YV3-GH-Yul" secondAttribute="bottom" constant="9" id="NvL-b8-QDl"/>
<constraint firstAttribute="bottom" secondItem="hMq-Ee-EJK" secondAttribute="bottom" constant="6" id="aef-Rh-49d"/>
<constraint firstItem="hMq-Ee-EJK" firstAttribute="top" secondItem="1Ho-Zz-KN0" secondAttribute="top" constant="6" id="csX-us-yCd"/>
<constraint firstAttribute="trailing" secondItem="hMq-Ee-EJK" secondAttribute="trailing" constant="8" id="xDE-tf-5mB"/>
<constraint firstItem="YV3-GH-Yul" firstAttribute="leading" secondItem="1Ho-Zz-KN0" secondAttribute="leading" constant="8" id="xyR-oc-iUp"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2Th-gL-oAN">
<rect key="frame" x="0.0" y="202" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2Th-gL-oAN" id="OFq-Mz-mbl">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="baL-Tb-bTJ">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="49" id="SaV-RG-DVL"/>
<constraint firstAttribute="height" constant="31" id="dXb-pb-etA"/>
@ -138,33 +156,38 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Empty view, no messages" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DoU-SU-Nek">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstItem="DoU-SU-Nek" firstAttribute="leading" secondItem="OFq-Mz-mbl" secondAttribute="leading" constant="8" id="A9k-hI-0BH"/>
<constraint firstAttribute="bottom" secondItem="baL-Tb-bTJ" secondAttribute="bottom" constant="6" id="Ff7-1T-EbZ"/>
<constraint firstItem="DoU-SU-Nek" firstAttribute="top" secondItem="OFq-Mz-mbl" secondAttribute="top" constant="10" id="Uji-LE-8IA"/>
<constraint firstAttribute="trailing" secondItem="baL-Tb-bTJ" secondAttribute="trailing" constant="8" id="dUp-7b-g3p"/>
<constraint firstItem="baL-Tb-bTJ" firstAttribute="leading" secondItem="DoU-SU-Nek" secondAttribute="trailing" constant="8" id="fxZ-zy-ksL"/>
<constraint firstAttribute="bottom" secondItem="DoU-SU-Nek" secondAttribute="bottom" constant="9" id="h0B-EX-3MW"/>
<constraint firstItem="baL-Tb-bTJ" firstAttribute="top" secondItem="OFq-Mz-mbl" secondAttribute="top" constant="6" id="v5e-xk-srk"/>
<constraint firstAttribute="centerY" secondItem="baL-Tb-bTJ" secondAttribute="centerY" id="hx4-cn-W0h"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Avatars" id="ns0-OO-PGu">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="hYS-4f-iL6">
<rect key="frame" x="0.0" y="289" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hYS-4f-iL6" id="dk1-tc-gux">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fLZ-NC-aPO">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="49" id="1lf-6y-hgz"/>
<constraint firstAttribute="height" constant="31" id="rdQ-ol-d20"/>
@ -175,29 +198,34 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Incoming avatars" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RUq-Pa-3nx">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstAttribute="centerY" secondItem="fLZ-NC-aPO" secondAttribute="centerY" id="17e-cC-bP4"/>
<constraint firstAttribute="bottom" secondItem="RUq-Pa-3nx" secondAttribute="bottom" constant="9" id="7Yt-uN-sOS"/>
<constraint firstItem="RUq-Pa-3nx" firstAttribute="top" secondItem="dk1-tc-gux" secondAttribute="top" constant="10" id="Aih-Lc-tq7"/>
<constraint firstItem="fLZ-NC-aPO" firstAttribute="leading" secondItem="RUq-Pa-3nx" secondAttribute="trailing" constant="8" id="Cfo-7m-Vyd"/>
<constraint firstAttribute="trailing" secondItem="fLZ-NC-aPO" secondAttribute="trailing" constant="8" id="Mgz-VG-tDn"/>
<constraint firstItem="fLZ-NC-aPO" firstAttribute="top" secondItem="dk1-tc-gux" secondAttribute="top" constant="6" id="S6i-he-vB9"/>
<constraint firstItem="RUq-Pa-3nx" firstAttribute="leading" secondItem="dk1-tc-gux" secondAttribute="leading" constant="8" id="mhd-oX-p53"/>
<constraint firstAttribute="bottom" secondItem="fLZ-NC-aPO" secondAttribute="bottom" constant="6" id="yyq-Sg-nJi"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="VF7-uo-6Pc">
<rect key="frame" x="0.0" y="333" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="VF7-uo-6Pc" id="zad-JQ-TRI">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LuM-mk-Zj6">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="height" constant="31" id="QXv-ty-g0B"/>
<constraint firstAttribute="width" constant="49" id="rZ3-cO-f8t"/>
@ -208,33 +236,38 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Outgoing avatars" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Rr-S8-Uae">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstAttribute="bottom" secondItem="LuM-mk-Zj6" secondAttribute="bottom" constant="6" id="1G7-8S-rYC"/>
<constraint firstAttribute="centerY" secondItem="LuM-mk-Zj6" secondAttribute="centerY" id="2oC-JM-LVI"/>
<constraint firstAttribute="bottom" secondItem="9Rr-S8-Uae" secondAttribute="bottom" constant="9" id="5xp-ez-tac"/>
<constraint firstItem="LuM-mk-Zj6" firstAttribute="leading" secondItem="9Rr-S8-Uae" secondAttribute="trailing" constant="8" id="C5c-2A-mli"/>
<constraint firstAttribute="trailing" secondItem="LuM-mk-Zj6" secondAttribute="trailing" constant="8" id="Lep-LY-D1h"/>
<constraint firstItem="LuM-mk-Zj6" firstAttribute="top" secondItem="zad-JQ-TRI" secondAttribute="top" constant="6" id="Y6a-JS-aLj"/>
<constraint firstItem="9Rr-S8-Uae" firstAttribute="leading" secondItem="zad-JQ-TRI" secondAttribute="leading" constant="8" id="Yao-VR-Is6"/>
<constraint firstItem="9Rr-S8-Uae" firstAttribute="top" secondItem="zad-JQ-TRI" secondAttribute="top" constant="10" id="Yiv-t6-Xj5"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Dynamic Behaviors" footerTitle="NOTE: This feature is experimental" id="o5m-OT-1Iw">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="q07-lZ-YdI">
<rect key="frame" x="0.0" y="420" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q07-lZ-YdI" id="btE-Mk-fSE">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uXC-2j-cgi">
<rect key="frame" x="263" y="6" width="51" height="31"/>
<animations/>
<constraints>
<constraint firstAttribute="height" constant="31" id="5bI-xQ-njj"/>
<constraint firstAttribute="width" constant="49" id="PG2-X2-FdD"/>
@ -245,21 +278,23 @@
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Springy bubbles" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3d2-fZ-dx9">
<rect key="frame" x="8" y="10" width="247" height="24"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<constraints>
<constraint firstItem="3d2-fZ-dx9" firstAttribute="leading" secondItem="btE-Mk-fSE" secondAttribute="leading" constant="8" id="6Cs-6l-Xzp"/>
<constraint firstItem="uXC-2j-cgi" firstAttribute="leading" secondItem="3d2-fZ-dx9" secondAttribute="trailing" constant="8" id="7Mq-HR-4nY"/>
<constraint firstItem="uXC-2j-cgi" firstAttribute="top" secondItem="btE-Mk-fSE" secondAttribute="top" constant="6" id="Ajq-5g-XKo"/>
<constraint firstAttribute="bottom" secondItem="3d2-fZ-dx9" secondAttribute="bottom" constant="9" id="EzH-aB-ePQ"/>
<constraint firstAttribute="bottom" secondItem="uXC-2j-cgi" secondAttribute="bottom" constant="6" id="RCb-Mi-FHX"/>
<constraint firstItem="3d2-fZ-dx9" firstAttribute="top" secondItem="btE-Mk-fSE" secondAttribute="top" constant="10" id="btF-q4-HJg"/>
<constraint firstAttribute="centerY" secondItem="uXC-2j-cgi" secondAttribute="centerY" id="zJf-Xj-C1X"/>
<constraint firstAttribute="trailing" secondItem="uXC-2j-cgi" secondAttribute="trailing" constant="8" id="zzu-aP-ZiL"/>
</constraints>
</tableViewCellContentView>
<animations/>
</tableViewCell>
</cells>
</tableViewSection>
@ -289,6 +324,7 @@
<navigationController definesPresentationContext="YES" id="s4z-xn-r6C" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="G3q-Gy-0Lf">
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="2Qx-iu-03V" kind="relationship" relationship="rootViewController" id="cuu-7c-yOr"/>
@ -309,6 +345,7 @@
<view key="view" contentMode="scaleToFill" id="Vop-TB-ImV">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="URv-4c-d6h"/>
@ -323,6 +360,7 @@
<navigationController definesPresentationContext="YES" id="JRd-Be-psV" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="YZb-OI-WKd">
<autoresizingMask key="autoresizingMask"/>
<animations/>
</navigationBar>
<connections>
<segue destination="rXs-qR-ns2" kind="relationship" relationship="rootViewController" id="8xe-QC-QaY"/>
@ -343,6 +381,7 @@
<view key="view" contentMode="scaleToFill" id="SsE-pA-zOd">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="gBw-Dh-o4F"/>
@ -352,9 +391,4 @@
<point key="canvasLocation" x="-1989" y="619"/>
</scene>
</scenes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View File

@ -35,7 +35,7 @@
@interface DemoMessagesViewController : JSQMessagesViewController <UIActionSheetDelegate>
@interface DemoMessagesViewController : JSQMessagesViewController <UIActionSheetDelegate, JSQMessagesComposerTextViewPasteDelegate>
@property (weak, nonatomic) id<JSQDemoViewControllerDelegate> delegateModal;

View File

@ -18,7 +18,6 @@
#import "DemoMessagesViewController.h"
@implementation DemoMessagesViewController
#pragma mark - View lifecycle
@ -44,6 +43,7 @@
self.senderId = kJSQDemoAvatarIdSquires;
self.senderDisplayName = kJSQDemoAvatarDisplayNameSquires;
self.inputToolbar.contentView.textView.pasteDelegate = self;
/**
* Load up our fake data for the demo
@ -68,13 +68,30 @@
style:UIBarButtonItemStyleBordered
target:self
action:@selector(receiveMessagePressed:)];
/**
* Register custom menu actions for cells.
*/
[JSQMessagesCollectionViewCell registerMenuAction:@selector(customAction:)];
/**
* OPT-IN: allow cells to be deleted
*/
[JSQMessagesCollectionViewCell registerMenuAction:@selector(delete:)];
/**
* Customize your toolbar buttons
*
* self.inputToolbar.contentView.leftBarButtonItem = custom button or nil to remove
* self.inputToolbar.contentView.rightBarButtonItem = custom button or nil to remove
*/
/**
* Set a maximum height for the input toolbar
*
* self.inputToolbar.maximumHeight = 150;
*/
}
- (void)viewWillAppear:(BOOL)animated
@ -102,6 +119,19 @@
#pragma mark - Custom menu actions for cells
- (void)didReceiveMenuWillShowNotification:(NSNotification *)notification
{
/**
* Display custom menu actions for cells.
*/
UIMenuController *menu = [notification object];
menu.menuItems = @[ [[UIMenuItem alloc] initWithTitle:@"Custom Action" action:@selector(customAction:)] ];
}
#pragma mark - Testing
- (void)pushMainViewController
@ -202,6 +232,18 @@
newMediaData = videoItemCopy;
}
else if ([copyMediaData isKindOfClass:[JSQAudioMediaItem class]]) {
JSQAudioMediaItem *audioItemCopy = [((JSQAudioMediaItem *)copyMediaData) copy];
audioItemCopy.appliesMediaViewMaskAsOutgoing = NO;
newMediaAttachmentCopy = [audioItemCopy.audioData copy];
/**
* Reset audio item to simulate "downloading" the audio
*/
audioItemCopy.audioData = nil;
newMediaData = audioItemCopy;
}
else {
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
}
@ -258,6 +300,10 @@
((JSQVideoMediaItem *)newMediaData).isReadyToPlay = YES;
[self.collectionView reloadData];
}
else if ([newMediaData isKindOfClass:[JSQAudioMediaItem class]]) {
((JSQAudioMediaItem *)newMediaData).audioData = newMediaAttachmentCopy;
[self.collectionView reloadData];
}
else {
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
}
@ -305,11 +351,13 @@
- (void)didPressAccessoryButton:(UIButton *)sender
{
[self.inputToolbar.contentView.textView resignFirstResponder];
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Media messages"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Send photo", @"Send location", @"Send video", nil];
otherButtonTitles:@"Send photo", @"Send location", @"Send video", @"Send audio", nil];
[sheet showFromToolbar:self.inputToolbar];
}
@ -317,6 +365,7 @@
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == actionSheet.cancelButtonIndex) {
[self.inputToolbar.contentView.textView becomeFirstResponder];
return;
}
@ -338,6 +387,10 @@
case 2:
[self.demoData addVideoMediaMessage];
break;
case 3:
[self.demoData addAudioMediaMessage];
break;
}
[JSQSystemSoundPlayer jsq_playMessageSentSound];
@ -354,6 +407,11 @@
return [self.demoData.messages objectAtIndex:indexPath.item];
}
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didDeleteMessageAtIndexPath:(NSIndexPath *)indexPath
{
[self.demoData.messages removeObjectAtIndex:indexPath.item];
}
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
/**
@ -504,6 +562,43 @@
#pragma mark - UICollectionView Delegate
#pragma mark - Custom menu items
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
{
if (action == @selector(customAction:)) {
return YES;
}
return [super collectionView:collectionView canPerformAction:action forItemAtIndexPath:indexPath withSender:sender];
}
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
{
if (action == @selector(customAction:)) {
[self customAction:sender];
return;
}
[super collectionView:collectionView performAction:action forItemAtIndexPath:indexPath withSender:sender];
}
- (void)customAction:(id)sender
{
NSLog(@"Custom action received! Sender: %@", sender);
[[[UIAlertView alloc] initWithTitle:@"Custom Action"
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil]
show];
}
#pragma mark - JSQMessages collection view flow layout delegate
#pragma mark - Adjusting cell label heights
@ -578,4 +673,23 @@
NSLog(@"Tapped cell at %@!", NSStringFromCGPoint(touchLocation));
}
#pragma mark - JSQMessagesComposerTextViewPasteDelegate methods
- (BOOL)composerTextView:(JSQMessagesComposerTextView *)textView shouldPasteWithSender:(id)sender
{
if ([UIPasteboard generalPasteboard].image) {
// If there's an image in the pasteboard, construct a media item with that image and `send` it.
JSQPhotoMediaItem *item = [[JSQPhotoMediaItem alloc] initWithImage:[UIPasteboard generalPasteboard].image];
JSQMessage *message = [[JSQMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName
date:[NSDate date]
media:item];
[self.demoData.messages addObject:message];
[self finishSendingMessage];
return NO;
}
return YES;
}
@end

View File

@ -58,4 +58,6 @@ static NSString * const kJSQDemoAvatarIdWoz = @"309-41802-93823";
- (void)addVideoMediaMessage;
- (void)addAudioMediaMessage;
@end

View File

@ -131,6 +131,7 @@
nil];
[self addPhotoMediaMessage];
[self addAudioMediaMessage];
/**
* Setting to load extra messages for testing/demo
@ -156,6 +157,17 @@
}
}
- (void)addAudioMediaMessage
{
NSString * sample = [[NSBundle mainBundle] pathForResource:@"jsq_messages_sample" ofType:@"m4a"];
NSData * audioData = [NSData dataWithContentsOfFile:sample];
JSQAudioMediaItem *audioItem = [[JSQAudioMediaItem alloc] initWithData:audioData];
JSQMessage *audioMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
displayName:kJSQDemoAvatarDisplayNameSquires
media:audioItem];
[self.messages addObject:audioMessage];
}
- (void)addPhotoMediaMessage
{
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]];

View File

@ -71,6 +71,12 @@
"idiom" : "ipad",
"filename" : "Icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon167.png",
"scale" : "2x"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>6.1.1</string>
<string>7.3.4</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>6.1.1</string>
<string>7.3.4</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>

View File

@ -38,16 +38,23 @@
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
return 4;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 2) {
return 1;
switch (section) {
case 0:
return 2;
case 1:
return 2;
case 2:
return 1;
case 3:
return 1;
default:
return 0;
}
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
@ -58,7 +65,7 @@
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 0) {
switch (indexPath.row) {
case 0:
@ -86,7 +93,14 @@
break;
}
}
else if (indexPath.section == 3) {
switch (indexPath.row) {
case 0:
cell.textLabel.text = @"Push view 2 levels";
break;
}
}
return cell;
}
@ -97,6 +111,8 @@
return @"Presentation";
case 2:
return @"Demo options";
case 3:
return @"Other testing";
default:
return nil;
}
@ -104,7 +120,7 @@
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return (section == [tableView numberOfSections] - 1) ? @"Copyright © 2014\nJesse Squires\nMIT License" : nil;
return (section == 2) ? @"Copyright © 2015\nJesse Squires\nMIT License" : nil;
}
#pragma mark - Table view delegate
@ -146,6 +162,19 @@
break;
}
}
else if (indexPath.section == 3) {
switch (indexPath.row) {
case 0:
{
UIViewController *blank = [[UIViewController alloc] initWithNibName:nil bundle:nil];
blank.title = @"Blank";
blank.view.backgroundColor = [UIColor lightGrayColor];
[self.navigationController pushViewController:blank animated:NO];
DemoMessagesViewController *vc = [DemoMessagesViewController messagesViewController];
[self.navigationController pushViewController:vc animated:YES];
}
}
}
}
#pragma mark - Segues

Binary file not shown.

View File

@ -0,0 +1,46 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// MIT License
// Copyright (c) 2014 Jesse Squires
// http://opensource.org/licenses/MIT
//
#import <XCTest/XCTest.h>
#import "NSBundle+JSQMessages.h"
@interface JSQMessagesNSBundleTests : XCTestCase
@end
@implementation JSQMessagesNSBundleTests
- (void)testMessagesBundle
{
XCTAssertNotNil([NSBundle jsq_messagesBundle]);
}
- (void)testAssetBundle
{
NSBundle *bundle = [NSBundle jsq_messagesAssetBundle];
XCTAssertNotNil(bundle);
XCTAssertEqualObjects(bundle.bundlePath.lastPathComponent, @"JSQMessagesAssets.bundle");
}
- (void)testLocalizedStringForKey
{
XCTAssertNotNil([NSBundle jsq_localizedStringForKey:@"send"]);
XCTAssertNotEqualObjects([NSBundle jsq_localizedStringForKey:@"send"], @"send");
XCTAssertNotNil([NSBundle jsq_localizedStringForKey:@"load_earlier_messages"]);
XCTAssertNotEqualObjects([NSBundle jsq_localizedStringForKey:@"load_earlier_messages"], @"load_earlier_messages");
XCTAssertNotNil([NSBundle jsq_localizedStringForKey:@"new_message"]);
XCTAssertNotEqualObjects([NSBundle jsq_localizedStringForKey:@"new_message"], @"new_message");
}
@end

View File

@ -10,8 +10,6 @@
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "JSQMessagesViewController.h"
#import "DemoMessagesViewController.h"
@ -48,14 +46,17 @@
XCTAssertNotNil(nib, @"Nib should not be nil");
JSQMessagesViewController *vc = [JSQMessagesViewController messagesViewController];
[vc view];
vc.senderId = @"senderId";
vc.senderDisplayName = @"senderDisplayName";
[vc beginAppearanceTransition:YES animated:NO];
[vc endAppearanceTransition];
XCTAssertNotNil(vc, @"View controller should not be nil");
XCTAssertNotNil(vc.view, @"View should not be nil");
XCTAssertNotNil(vc.collectionView, @"Collection view should not be nil");
XCTAssertNotNil(vc.inputToolbar, @"Input toolbar should not be nil");
XCTAssertEqualObjects(vc.senderId, @"JSQDefaultSender", @"Property should be equal to default value");
XCTAssertEqualObjects(vc.senderDisplayName, @"JSQDefaultSender", @"Property should be equal to default value");
XCTAssertEqual(vc.automaticallyAdjustsScrollViewInsets, YES, @"Property should be equal to default value");
XCTAssertEqualObjects(vc.incomingCellIdentifier, [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier], @"Property should be equal to default value");
@ -68,7 +69,12 @@
- (void)testJSQMessagesViewControllerSubclassInitProgramatically
{
DemoMessagesViewController *demoVC = [DemoMessagesViewController messagesViewController];
[demoVC view];
demoVC.senderId = @"senderId";
demoVC.senderDisplayName = @"senderDisplayName";
[demoVC beginAppearanceTransition:YES animated:NO];
[demoVC endAppearanceTransition];
XCTAssertNotNil(demoVC, @"View controller should not be nil");
XCTAssertTrue([demoVC isKindOfClass:[DemoMessagesViewController class]], @"View controller should be kind of class: %@", [DemoMessagesViewController class]);
XCTAssertNotNil(demoVC.view, @"View should not be nil");
@ -82,7 +88,12 @@
XCTAssertNotNil(mainSB, @"Storyboard should not be nil");
DemoMessagesViewController *demoVC = [mainSB instantiateViewControllerWithIdentifier:@"DemoVC"];
[demoVC view];
demoVC.senderId = @"senderId";
demoVC.senderDisplayName = @"senderDisplayName";
[demoVC beginAppearanceTransition:YES animated:NO];
[demoVC endAppearanceTransition];
XCTAssertNotNil(demoVC, @"View controller should not be nil");
XCTAssertTrue([demoVC isKindOfClass:[DemoMessagesViewController class]], @"View controller should be kind of class: %@", [DemoMessagesViewController class]);
XCTAssertNotNil(demoVC.view, @"View should not be nil");
@ -90,14 +101,4 @@
XCTAssertNotNil(demoVC.inputToolbar, @"Input toolbar should not be nil");
}
- (void)testViewConfiguration
{
JSQMessagesViewController *vc = [JSQMessagesViewController messagesViewController];
id mockVC = [OCMockObject partialMockForObject:vc];
[[mockVC expect] jsq_configureMessagesViewController];
[vc view];
[mockVC verify];
}
@end

View File

@ -98,7 +98,7 @@
NSString *relativeDateString = [[JSQMessagesTimestampFormatter sharedFormatter] relativeDateForDate:date];
XCTAssertEqualObjects(relativeDateString, @"Today", @"Relative date string shoudl return expected value");
XCTAssertEqualObjects(relativeDateString, @"Today", @"Relative date string should return expected value");
}
@end

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.hexedbits.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

View File

@ -0,0 +1,77 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// MIT License
// Copyright (c) 2014 Jesse Squires
// http://opensource.org/licenses/MIT
//
#import <XCTest/XCTest.h>
#import "JSQAudioMediaItem.h"
@interface JSQAudioMediaItemTests : XCTestCase
@end
@implementation JSQAudioMediaItemTests
- (void)setUp
{
[super setUp];
}
- (void)tearDown
{
[super tearDown];
}
- (void)testAudioItemInit
{
JSQAudioMediaItem *item = [[JSQAudioMediaItem alloc] initWithData:[NSData data]];
XCTAssertNotNil(item);
}
- (void)testAudioItemIsEqual
{
NSString * sample = [[NSBundle mainBundle] pathForResource:@"jsq_messages_sample" ofType:@"m4a"];
JSQAudioMediaItem *item = [[JSQAudioMediaItem alloc] initWithData:[NSData dataWithContentsOfFile:sample]];
JSQAudioMediaItem *copy = [item copy];
XCTAssertEqualObjects(item, copy, @"Copied items should be equal");
XCTAssertEqual([item hash], [copy hash], @"Copied item hashes should be equal");
XCTAssertEqualObjects(item, item, @"Item should be equal to itself");
}
- (void)testAudioItemArchiving
{
NSString * sample = [[NSBundle mainBundle] pathForResource:@"jsq_messages_sample" ofType:@"m4a"];
JSQAudioMediaItem *item = [[JSQAudioMediaItem alloc] initWithData:[NSData dataWithContentsOfFile:sample]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
JSQAudioMediaItem *unarchivedItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
XCTAssertEqualObjects(item, unarchivedItem);
}
- (void)testMediaDataProtocol
{
JSQAudioMediaItem *item = [[JSQAudioMediaItem alloc] init];
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
XCTAssertNotNil([item mediaPlaceholderView]);
XCTAssertNil([item mediaView], @"Media view should be nil if image is nil");
NSString * sample = [[NSBundle mainBundle] pathForResource:@"jsq_messages_sample" ofType:@"m4a"];
item.audioData = [NSData dataWithContentsOfFile:sample];
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
}
@end

View File

@ -54,7 +54,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
[self waitForExpectationsWithTimeout:15 handler:^(NSError *error) {
XCTAssertNil(error, @"Expectation should not error");
}];

View File

@ -10,7 +10,7 @@
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
//#import <OCMock/OCMock.h>
#import "JSQMessage.h"
@ -30,6 +30,10 @@
- (BOOL)isEqual:(id)object { return YES; }
- (NSUInteger)hash { return 10000; }
- (NSUInteger)mediaHash { return self.hash; }
@end
@ -40,7 +44,7 @@
@property (strong, nonatomic) NSString *senderId;
@property (strong, nonatomic) NSString *senderDisplayName;
@property (strong, nonatomic) NSDate *date;
@property (strong, nonatomic) id<JSQMessageMediaData> mockMediaData;
@property (strong, nonatomic) FakeMedia *fakeMediaData;
@end
@ -53,7 +57,7 @@
self.senderId = @"324543-43556-212343";
self.senderDisplayName = @"Jesse Squires";
self.date = [NSDate date];
self.mockMediaData = [OCMockObject mockForProtocol:@protocol(JSQMessageMediaData)];
self.fakeMediaData = [FakeMedia new];
}
- (void)tearDown
@ -61,7 +65,7 @@
self.senderId = nil;
self.senderDisplayName = nil;
self.date = nil;
self.mockMediaData = nil;
self.fakeMediaData = nil;
[super tearDown];
}
@ -70,13 +74,12 @@
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName
date:self.date
media:self.mockMediaData];
media:self.fakeMediaData];
XCTAssertNotNil(msg, @"Message should not be nil");
}
- (void)testMediaMessageInvalidInit
{
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw");
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"Invalid init should throw");
}
@ -85,7 +88,7 @@
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName
date:self.date
media:self.mockMediaData];
media:self.fakeMediaData];
JSQMessage *copy = [msg copy];
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");

View File

@ -60,7 +60,6 @@
- (void)testTextMessageInvalidInit
{
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw");
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil text:nil], @"Invalid init should throw");
}

View File

@ -32,7 +32,6 @@
- (void)testInitInvalid
{
XCTAssertThrows([[JSQMessagesAvatarImage alloc] init], @"Invalid init should throw");
XCTAssertThrows([JSQMessagesAvatarImage avatarImageWithPlaceholder:nil], @"Invalid init should throw");
XCTAssertThrows([[JSQMessagesAvatarImage alloc] initWithAvatarImage:nil highlightedImage:nil placeholderImage:nil], @"Invalid init should throw");
}

View File

@ -34,7 +34,6 @@
- (void)testInitInvalid
{
XCTAssertThrows([[JSQMessagesBubbleImage alloc] init], @"Invalid init should throw");
XCTAssertThrows([[JSQMessagesBubbleImage alloc] initWithMessageBubbleImage:nil highlightedImage:nil], @"Invalid init should throw");
}

View File

@ -39,7 +39,7 @@
XCTAssertNotNil(view, @"Collection view should not be nil");
XCTAssertEqualObjects(view.backgroundColor, [UIColor whiteColor], @"Property should be equal to default value");
XCTAssertEqual(view.keyboardDismissMode, UIScrollViewKeyboardDismissModeInteractive, @"Property should be equal to default value");
XCTAssertEqual(view.keyboardDismissMode, UIScrollViewKeyboardDismissModeNone, @"Property should be equal to default value");
XCTAssertEqual(view.alwaysBounceVertical, YES, @"Property should be equal to default value");
XCTAssertEqual(view.bounces, YES, @"Property should be equal to default value");
}

View File

@ -12,6 +12,7 @@
#import "JSQMessagesViewController.h"
#import "JSQMessagesInputToolbar.h"
#import "DemoMessagesViewController.h"
@interface JSQMessagesInputToolbarTests : XCTestCase
@ -34,11 +35,36 @@
{
JSQMessagesViewController *vc = [JSQMessagesViewController messagesViewController];
[vc loadView];
JSQMessagesInputToolbar *toolbar = vc.inputToolbar;
XCTAssertNotNil(toolbar, @"Toolbar should not be nil");
XCTAssertNotNil(toolbar.contentView, @"Toolbar content view should not be nil");
XCTAssertEqual(toolbar.sendButtonOnRight, YES, @"Property should be equal to default value");
}
- (void)testSetMaximumHeight
{
UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
XCTAssertNotNil(mainSB, @"Storyboard should not be nil");
DemoMessagesViewController *demoVC = [mainSB instantiateViewControllerWithIdentifier:@"DemoVC"];
[demoVC beginAppearanceTransition:YES animated:NO];
[demoVC endAppearanceTransition];
XCTAssertEqual(demoVC.inputToolbar.maximumHeight, NSNotFound, @"maximumInputToolbarHeight should equal default value");
demoVC.inputToolbar.maximumHeight = 54;
CGRect newBounds = demoVC.inputToolbar.bounds;
newBounds.size.height = 100;
demoVC.inputToolbar.bounds = newBounds;
XCTAssertEqual(CGRectGetHeight(demoVC.inputToolbar.bounds), 100);
[demoVC.view setNeedsUpdateConstraints];
[demoVC.view setNeedsLayout];
[demoVC.view layoutIfNeeded];
XCTAssertLessThanOrEqual(CGRectGetHeight(demoVC.inputToolbar.frame), 54, @"Toolbar height should be <= to maximumInputToolbarHeight");
}
@end

View File

@ -1,21 +1,26 @@
Pod::Spec.new do |s|
s.name = 'JSQMessagesViewController'
s.version = '6.1.1'
s.summary = 'An elegant messages UI library for iOS.'
s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController'
s.license = 'MIT'
s.screenshots = ['https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png']
s.author = { 'Jesse Squires' => 'jesse.squires.developer@gmail.com' }
s.social_media_url = 'https://twitter.com/jesse_squires'
s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version.to_s }
s.platform = :ios, '7.0'
s.source_files = 'JSQMessagesViewController/**/*.{h,m}'
s.resources = 'JSQMessagesViewController/Assets/JSQMessagesAssets.bundle', 'JSQMessagesViewController/Assets/Strings/*.lproj', 'JSQMessagesViewController/**/*.{xib}',
s.frameworks = 'QuartzCore', 'CoreGraphics', 'CoreLocation', 'MapKit', 'UIKit', 'Foundation'
s.requires_arc = true
s.name = 'JSQMessagesViewController'
s.version = '7.3.4'
s.summary = 'An elegant messages UI library for iOS.'
s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController'
s.license = 'MIT'
s.platform = :ios, '7.0'
s.dependency 'JSQSystemSoundPlayer', '~> 2.0.0'
s.author = 'Jesse Squires'
s.social_media_url = 'https://twitter.com/jesse_squires'
s.screenshots = ['https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png']
s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version }
s.source_files = 'JSQMessagesViewController/**/*.{h,m}'
s.resources = ['JSQMessagesViewController/Assets/JSQMessagesAssets.bundle', 'JSQMessagesViewController/**/*.{xib}']
s.frameworks = 'QuartzCore', 'CoreGraphics', 'CoreLocation', 'MapKit', 'AVFoundation'
s.requires_arc = true
s.dependency 'JSQSystemSoundPlayer', '~> 2.0.1'
end

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Load Earlier Messages";
"send" = "Send";
"new_message" = "New Message";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: media message";
"accessory_button_accessibility_label" = "Share media";
"new_message_received_accessibility_announcement" = "New message received";

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "تحميل الرسائل السابقة";
"send" = "أرسال";
"new_message" = "رسالة جديدة";

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Ältere Nachrichten laden";
"send" = "Senden";
"new_message" = "Neue Nachricht";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: media Nachricht";
"accessory_button_accessibility_label" = "Aktien media";
"new_message_received_accessibility_announcement" = "Neue Nachricht empfangen";

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Load Earlier Messages";
"send" = "Send";
"new_message" = "New Message";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: media message";
"accessory_button_accessibility_label" = "Share media";
"new_message_received_accessibility_announcement" = "New message received";

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Cargar mensajes anteriores";
"send" = "Enviar";
"new_message" = "Nuevo mensaje";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: imagen";
"accessory_button_accessibility_label" = "Intercambio de archivos";
"new_message_received_accessibility_announcement" = "mensaje recibido";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Laad eerdere berichten";
"load_earlier_messages" = "Lataa aiempia viestejä";
"Send" = "Stuur";
"send" = "Lähetä";
"New Message" = "Nieuw bericht";
"new_message" = "Uusi viesti";

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Messages précedents";
"send" = "Envoyer";
"new_message" = "Nouveau message";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: image";
"accessory_button_accessibility_label" = "Partager fichier";
"new_message_received_accessibility_announcement" = "Nouveau message reçu";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "טען הודעות קודמות";
"send" = "שלח";
"new_message" = "הודעה חדשה";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Učitaj ranije poruke";
"send" = "Šalji";
"new_message" = "Nova poruka";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "載入之前的訊息";
"load_earlier_messages" = "Muat Pesan Sebelumnya";
"Send" = "傳送";
"send" = "Kirim";
"New Message" = "新信息";
"new_message" = "Pesan Baru";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Cargar mensajes anteriores";
"load_earlier_messages" = "Carica messaggi precedenti";
"Send" = "Enviar";
"send" = "Invia";
"New Message" = "Nuevo mensaje";
"new_message" = "Nuovo Messaggio";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "古いメッセージを読み込む";
"send" = "送信";
"new_message" = "新しいメッセージ";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "이전 메시지 불러오기";
"send" = "전송";
"new_message" = "새로운 메시지";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Load Earlier Messages";
"load_earlier_messages" = "Muat Turun Mesej Lama";
"Send" = "Send";
"send" = "Hantar";
"New Message" = "New Message";
"new_message" = "Mesej Baru";

View File

@ -0,0 +1,37 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Last tidligere beskjeder";
"send" = "Send";
"new_message" = "Ny melding";
"text_message_accessibility_label" = "%@: %@";
"media_message_accessibility_label" = "%@: mediamelding";
"accessory_button_accessibility_label" = "Del media";
"new_message_received_accessibility_announcement" = "Ny melding mottatt";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Messages précedents";
"load_earlier_messages" = "Laad eerdere berichten";
"Send" = "Envoi";
"send" = "Stuur";
"New Message" = "Nouveau message";
"new_message" = "Nieuw bericht";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Otwórz wcześniejsze wiadomości";
"send" = "Wyślij";
"new_message" = "Nowa wiadomość";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Ältere Nachrichten laden";
"load_earlier_messages" = "Carregar mensagens anteriores";
"Send" = "Senden";
"send" = "Enviar";
"New Message" = "Neue Nachricht";
"new_message" = "Nova Mensagem";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Încărcați mesajele anterioare";
"send" = "Trimiteți";
"new_message" = "Mesaj nou";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Предыдущие сообщения";
"load_earlier_messages" = "Предыдущие сообщения";
"Send" = "Отпр";
"send" = "Отпр";
"New Message" = "Сообщение";
"new_message" = "Сообщение";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "โหลดข้อความก่อนหน้า";
"send" = "ส่ง";
"new_message" = "ข้อความใหม่";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Eski mesajları yükle";
"load_earlier_messages" = "Eski mesajları yükle";
"Send" = "Gönder";
"send" = "Gönder";
"New Message" = "Yeni Mesaj";
"new_message" = "Yeni Mesaj";

View File

@ -0,0 +1,29 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"load_earlier_messages" = "Tải thêm tin nhắn";
"send" = "Gửi";
"new_message" = "Tin nhắn mới";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Load Earlier Messages";
"load_earlier_messages" = "载入较早的信息";
"Send" = "Send";
"send" = "发送";
"New Message" = "New Message";
"new_message" = "新信息";

View File

@ -22,8 +22,8 @@
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "载入较早的信息";
"load_earlier_messages" = "載入之前的訊息";
"Send" = "发送";
"send" = "傳送";
"New Message" = "新信息";
"new_message" = "新信息";

View File

@ -1,29 +0,0 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "טען הודעות קודמות";
"Send" = "שלח";
"New Message" = "הודעה חדשה";

View File

@ -1,29 +0,0 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Carica messaggi precedenti";
"Send" = "Invia";
"New Message" = "Nuovo Messaggio";

View File

@ -1,29 +0,0 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Otwórz wcześniejsze wiadomości";
"Send" = "Wyślij";
"New Message" = "Nowa wiadomość";

View File

@ -1,29 +0,0 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Carregar mensagens anteriore";
"Send" = "Enviar";
"New Message" = "Nova Mensagem";

View File

@ -1,29 +0,0 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
// ********************************
// Special thanks to the localization contributors!
//
// https://github.com/jessesquires/JSQMessagesViewController/issues/237
// ********************************
"Load Earlier Messages" = "Încărcați mesajele anterioare";
"Send" = "Trimiteți";
"New Message" = "Mesaj nou";

View File

@ -18,34 +18,58 @@
#import "JSQSystemSoundPlayer+JSQMessages.h"
static NSString * const kJSQMessageReceivedSoundName = @"JSQMessagesAssets.bundle/Sounds/message_received";
static NSString * const kJSQMessageSentSoundName = @"JSQMessagesAssets.bundle/Sounds/message_sent";
#import "NSBundle+JSQMessages.h"
static NSString * const kJSQMessageReceivedSoundName = @"message_received";
static NSString * const kJSQMessageSentSoundName = @"message_sent";
@implementation JSQSystemSoundPlayer (JSQMessages)
#pragma mark - Public
+ (void)jsq_playMessageReceivedSound
{
[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:kJSQMessageReceivedSoundName
fileExtension:kJSQSystemSoundTypeAIFF];
[self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageReceivedSoundName asAlert:NO];
}
+ (void)jsq_playMessageReceivedAlert
{
[[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:kJSQMessageReceivedSoundName
fileExtension:kJSQSystemSoundTypeAIFF];
[self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageReceivedSoundName asAlert:YES];
}
+ (void)jsq_playMessageSentSound
{
[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:kJSQMessageSentSoundName
fileExtension:kJSQSystemSoundTypeAIFF];
[self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageSentSoundName asAlert:NO];
}
+ (void)jsq_playMessageSentAlert
{
[[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:kJSQMessageSentSoundName
fileExtension:kJSQSystemSoundTypeAIFF];
[self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageSentSoundName asAlert:YES];
}
#pragma mark - Private
+ (void)jsq_playSoundFromJSQMessagesBundleWithName:(NSString *)soundName asAlert:(BOOL)asAlert
{
// save sound player original bundle
NSString *originalPlayerBundleIdentifier = [JSQSystemSoundPlayer sharedPlayer].bundle.bundleIdentifier;
// search for sounds in this library's bundle
[JSQSystemSoundPlayer sharedPlayer].bundle = [NSBundle jsq_messagesBundle];
NSString *fileName = [NSString stringWithFormat:@"JSQMessagesAssets.bundle/Sounds/%@", soundName];
if (asAlert) {
[[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
}
else {
[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
}
// restore original bundle
[JSQSystemSoundPlayer sharedPlayer].bundle = [NSBundle bundleWithIdentifier:originalPlayerBundleIdentifier];
}
@end

View File

@ -0,0 +1,42 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import <Foundation/Foundation.h>
@interface NSBundle (JSQMessages)
/**
* @return The bundle for JSQMessagesViewController.
*/
+ (NSBundle *)jsq_messagesBundle;
/**
* @return The bundle for assets in JSQMessagesViewController.
*/
+ (NSBundle *)jsq_messagesAssetBundle;
/**
* Returns a localized version of the string designated by the specified key and residing in the JSQMessages table.
*
* @param key The key for a string in the JSQMessages table.
*
* @return A localized version of the string designated by key in the JSQMessages table.
*/
+ (NSString *)jsq_localizedStringForKey:(NSString *)key;
@end

View File

@ -0,0 +1,44 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import "NSBundle+JSQMessages.h"
#import "JSQMessagesViewController.h"
@implementation NSBundle (JSQMessages)
+ (NSBundle *)jsq_messagesBundle
{
return [NSBundle bundleForClass:[JSQMessagesViewController class]];
}
+ (NSBundle *)jsq_messagesAssetBundle
{
NSString *bundleResourcePath = [NSBundle jsq_messagesBundle].resourcePath;
NSString *assetPath = [bundleResourcePath stringByAppendingPathComponent:@"JSQMessagesAssets.bundle"];
return [NSBundle bundleWithPath:assetPath];
}
+ (NSString *)jsq_localizedStringForKey:(NSString *)key
{
// In Signal, we prefer to use our own translations to the incomplete translations in this bundle
// return NSLocalizedStringFromTableInBundle(key, @"JSQMessages", [NSBundle jsq_messagesAssetBundle], nil);
return NSLocalizedString(key, nil);
}
@end

View File

@ -25,4 +25,9 @@
*/
+ (BOOL)jsq_isCurrentDeviceBeforeiOS8;
/**
* @return Whether or not the current device is running a version of iOS after 9.0.
*/
+ (BOOL)jsq_isCurrentDeviceAfteriOS9;
@end

View File

@ -23,7 +23,13 @@
+ (BOOL)jsq_isCurrentDeviceBeforeiOS8
{
// iOS < 8.0
return [[UIDevice currentDevice].systemVersion compare:@"8.0.0" options:NSNumericSearch] == NSOrderedAscending;
return [[UIDevice currentDevice].systemVersion compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending;
}
+ (BOOL)jsq_isCurrentDeviceAfteriOS9
{
// iOS > 9.0
return [[UIDevice currentDevice].systemVersion compare:@"9.0" options:NSNumericSearch] == NSOrderedDescending;
}
@end

View File

@ -52,7 +52,7 @@
/**
* @return The compact message bubble image.
*
* @disscussion This is the default bubble image used by `JSQMessagesBubbleImageFactory`.
* @discussion This is the default bubble image used by `JSQMessagesBubbleImageFactory`.
*/
+ (UIImage *)jsq_bubbleCompactImage;
@ -76,4 +76,9 @@
*/
+ (UIImage *)jsq_defaultPlayImage;
/**
* @return The default pause icon image.
*/
+ (UIImage *)jsq_defaultPauseImage;
@end

View File

@ -18,6 +18,9 @@
#import "UIImage+JSQMessages.h"
#import "NSBundle+JSQMessages.h"
@implementation UIImage (JSQMessages)
- (UIImage *)jsq_imageMaskedWithColor:(UIColor *)maskColor
@ -47,7 +50,9 @@
+ (UIImage *)jsq_bubbleImageFromBundleWithName:(NSString *)name
{
return [UIImage imageNamed:[NSString stringWithFormat:@"JSQMessagesAssets.bundle/Images/%@", name]];
NSBundle *bundle = [NSBundle jsq_messagesAssetBundle];
NSString *path = [bundle pathForResource:name ofType:@"png" inDirectory:@"Images"];
return [UIImage imageWithContentsOfFile:path];
}
+ (UIImage *)jsq_bubbleRegularImage
@ -95,4 +100,9 @@
return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
}
+ (UIImage *)jsq_defaultPauseImage
{
return [UIImage jsq_bubbleImageFromBundleWithName:@"pause"];
}
@end

View File

@ -59,13 +59,6 @@ FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeybo
*/
- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame;
/**
* Tells the delegate that the keyboard has been hidden.
*
* @param keyboardController The keyboard controller that is notifying the delegate.
*/
- (void)keyboardControllerKeyboardDidHide:(JSQMessagesKeyboardController *)keyboardController;
@end
@ -117,6 +110,11 @@ FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeybo
*/
@property (assign, nonatomic, readonly) CGRect currentKeyboardFrame;
/**
* Not a valid initializer.
*/
- (id)init NS_UNAVAILABLE;
/**
* Creates a new keyboard controller object with the specified textView, contextView, panGestureRecognizer, and delegate.
*
@ -130,7 +128,7 @@ FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeybo
- (instancetype)initWithTextView:(UITextView *)textView
contextView:(UIView *)contextView
panGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer
delegate:(id<JSQMessagesKeyboardControllerDelegate>)delegate;
delegate:(id<JSQMessagesKeyboardControllerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
/**
* Tells the keyboard controller that it should begin listening for system keyboard notifications.

View File

@ -39,24 +39,7 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
@property (assign, nonatomic) BOOL jsq_isObserving;
@property (weak, nonatomic) UIView *keyboardView;
- (void)jsq_registerForNotifications;
- (void)jsq_unregisterForNotifications;
- (void)jsq_didReceiveKeyboardDidShowNotification:(NSNotification *)notification;
- (void)jsq_didReceiveKeyboardWillChangeFrameNotification:(NSNotification *)notification;
- (void)jsq_didReceiveKeyboardDidChangeFrameNotification:(NSNotification *)notification;
- (void)jsq_didReceiveKeyboardDidHideNotification:(NSNotification *)notification;
- (void)jsq_handleKeyboardNotification:(NSNotification *)notification completion:(JSQAnimationCompletionBlock)completion;
- (void)jsq_setKeyboardViewHidden:(BOOL)hidden;
- (void)jsq_notifyKeyboardFrameNotificationForFrame:(CGRect)frame;
- (void)jsq_removeKeyboardFrameObserver;
- (void)jsq_handlePanGestureRecognizer:(UIPanGestureRecognizer *)pan;
@property (strong, nonatomic) UIView *keyboardView;
@end
@ -75,7 +58,7 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
NSParameterAssert(textView != nil);
NSParameterAssert(contextView != nil);
NSParameterAssert(panGestureRecognizer != nil);
self = [super init];
if (self) {
_textView = textView;
@ -91,11 +74,8 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
{
[self jsq_removeKeyboardFrameObserver];
[self jsq_unregisterForNotifications];
_textView = nil;
_contextView = nil;
_panGestureRecognizer = nil;
_delegate = nil;
_keyboardView = nil;
}
#pragma mark - Setters
@ -105,15 +85,15 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
if (_keyboardView) {
[self jsq_removeKeyboardFrameObserver];
}
_keyboardView = keyboardView;
if (keyboardView && !_jsq_isObserving) {
[_keyboardView addObserver:self
forKeyPath:NSStringFromSelector(@selector(frame))
options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew)
context:kJSQMessagesKeyboardControllerKeyValueObservingContext];
_jsq_isObserving = YES;
}
}
@ -130,7 +110,7 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
if (!self.keyboardIsVisible) {
return CGRectNull;
}
return self.keyboardView.frame;
}
@ -141,16 +121,18 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
if (self.textView.inputAccessoryView == nil) {
self.textView.inputAccessoryView = [[UIView alloc] init];
}
[self jsq_registerForNotifications];
}
- (void)endListeningForKeyboard
{
[self jsq_unregisterForNotifications];
[self jsq_setKeyboardViewHidden:NO];
self.keyboardView = nil;
// No need to set keyboardView to nil here
// Plus we need it for future "dismiss keyboard" gesture recognition.
// self.keyboardView = nil;
}
#pragma mark - Notifications
@ -158,22 +140,22 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)jsq_registerForNotifications
{
[self jsq_unregisterForNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(jsq_didReceiveKeyboardDidShowNotification:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(jsq_didReceiveKeyboardWillChangeFrameNotification:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(jsq_didReceiveKeyboardDidChangeFrameNotification:)
name:UIKeyboardDidChangeFrameNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(jsq_didReceiveKeyboardDidHideNotification:)
name:UIKeyboardDidHideNotification
@ -187,9 +169,24 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)jsq_didReceiveKeyboardDidShowNotification:(NSNotification *)notification
{
self.keyboardView = self.textView.inputAccessoryView.superview;
UIView *keyboardViewProxy = self.textView.inputAccessoryView.superview;
if ([UIDevice jsq_isCurrentDeviceAfteriOS9]) {
NSPredicate *windowPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", NSClassFromString(@"UIRemoteKeyboardWindow")];
UIWindow *keyboardWindow = [[UIApplication sharedApplication].windows filteredArrayUsingPredicate:windowPredicate].firstObject;
for (UIView *subview in keyboardWindow.subviews) {
for (UIView *hostview in subview.subviews) {
if ([hostview isMemberOfClass:NSClassFromString(@"UIInputSetHostView")]) {
keyboardViewProxy = hostview;
break;
}
}
}
self.keyboardView = keyboardViewProxy;
}
[self jsq_setKeyboardViewHidden:NO];
[self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
[self.panGestureRecognizer addTarget:self action:@selector(jsq_handlePanGestureRecognizer:)];
}];
@ -203,38 +200,36 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)jsq_didReceiveKeyboardDidChangeFrameNotification:(NSNotification *)notification
{
[self jsq_setKeyboardViewHidden:NO];
[self jsq_handleKeyboardNotification:notification completion:nil];
}
- (void)jsq_didReceiveKeyboardDidHideNotification:(NSNotification *)notification
{
self.keyboardView = nil;
[self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
[self.panGestureRecognizer removeTarget:self action:NULL];
[self.delegate keyboardControllerKeyboardDidHide:self];
}];
}
- (void)jsq_handleKeyboardNotification:(NSNotification *)notification completion:(JSQAnimationCompletionBlock)completion
{
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardEndFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
if (CGRectIsNull(keyboardEndFrame)) {
return;
}
UIViewAnimationCurve animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
NSInteger animationCurveOption = (animationCurve << 16);
double animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardEndFrameConverted = [self.contextView convertRect:keyboardEndFrame fromView:nil];
[UIView animateWithDuration:animationDuration
delay:0.0
options:animationCurveOption
@ -259,31 +254,37 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)jsq_notifyKeyboardFrameNotificationForFrame:(CGRect)frame
{
[self.delegate keyboardController:self keyboardDidChangeFrame:frame];
[[NSNotificationCenter defaultCenter] postNotificationName:JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame
object:self
userInfo:@{ JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame : [NSValue valueWithCGRect:frame] }];
}
- (void)jsq_resetKeyboardAndTextView
{
[self jsq_setKeyboardViewHidden:YES];
[self jsq_removeKeyboardFrameObserver];
[self.textView resignFirstResponder];
}
#pragma mark - Key-value observing
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == kJSQMessagesKeyboardControllerKeyValueObservingContext) {
if (object == self.keyboardView && [keyPath isEqualToString:NSStringFromSelector(@selector(frame))]) {
CGRect oldKeyboardFrame = [[change objectForKey:NSKeyValueChangeOldKey] CGRectValue];
CGRect newKeyboardFrame = [[change objectForKey:NSKeyValueChangeNewKey] CGRectValue];
if (CGRectEqualToRect(newKeyboardFrame, oldKeyboardFrame) || CGRectIsNull(newKeyboardFrame)) {
return;
}
// do not convert frame to contextView coordinates here
// KVO is triggered during panning (see below)
// panning occurs in contextView coordinates already
[self jsq_notifyKeyboardFrameNotificationForFrame:newKeyboardFrame];
CGRect keyboardEndFrameConverted = [self.contextView convertRect:newKeyboardFrame
fromView:self.keyboardView.superview];
[self jsq_notifyKeyboardFrameNotificationForFrame:keyboardEndFrameConverted];
}
}
}
@ -293,14 +294,14 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
if (!_jsq_isObserving) {
return;
}
@try {
[_keyboardView removeObserver:self
forKeyPath:NSStringFromSelector(@selector(frame))
context:kJSQMessagesKeyboardControllerKeyValueObservingContext];
}
@catch (NSException * __unused exception) { }
_jsq_isObserving = NO;
}
@ -308,42 +309,42 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)jsq_handlePanGestureRecognizer:(UIPanGestureRecognizer *)pan
{
CGPoint touch = [pan locationInView:self.contextView];
CGPoint touch = [pan locationInView:self.contextView.window];
// system keyboard is added to a new UIWindow, need to operate in window coordinates
// also, keyboard always slides from bottom of screen, not the bottom of a view
CGFloat contextViewWindowHeight = CGRectGetHeight(self.contextView.window.frame);
if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
// handle iOS 7 bug when rotating to landscape
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
contextViewWindowHeight = CGRectGetWidth(self.contextView.window.frame);
}
}
CGFloat keyboardViewHeight = CGRectGetHeight(self.keyboardView.frame);
CGFloat dragThresholdY = (contextViewWindowHeight - keyboardViewHeight - self.keyboardTriggerPoint.y);
CGRect newKeyboardViewFrame = self.keyboardView.frame;
BOOL userIsDraggingNearThresholdForDismissing = (touch.y > dragThresholdY);
self.keyboardView.userInteractionEnabled = !userIsDraggingNearThresholdForDismissing;
switch (pan.state) {
case UIGestureRecognizerStateChanged:
{
newKeyboardViewFrame.origin.y = touch.y + self.keyboardTriggerPoint.y;
// bound frame between bottom of view and height of keyboard
newKeyboardViewFrame.origin.y = MIN(newKeyboardViewFrame.origin.y, contextViewWindowHeight);
newKeyboardViewFrame.origin.y = MAX(newKeyboardViewFrame.origin.y, contextViewWindowHeight - keyboardViewHeight);
if (CGRectGetMinY(newKeyboardViewFrame) == CGRectGetMinY(self.keyboardView.frame)) {
return;
}
[UIView animateWithDuration:0.0
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionTransitionNone
@ -353,22 +354,23 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
completion:nil];
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
{
BOOL keyboardViewIsHidden = (CGRectGetMinY(self.keyboardView.frame) >= contextViewWindowHeight);
if (keyboardViewIsHidden) {
[self jsq_resetKeyboardAndTextView];
return;
}
CGPoint velocity = [pan velocityInView:self.contextView];
BOOL userIsScrollingDown = (velocity.y > 0.0f);
BOOL shouldHide = (userIsScrollingDown && userIsDraggingNearThresholdForDismissing);
newKeyboardViewFrame.origin.y = shouldHide ? contextViewWindowHeight : (contextViewWindowHeight - keyboardViewHeight);
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationCurveEaseOut
@ -377,11 +379,9 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
}
completion:^(BOOL finished) {
self.keyboardView.userInteractionEnabled = !shouldHide;
if (shouldHide) {
[self jsq_setKeyboardViewHidden:YES];
[self jsq_removeKeyboardFrameObserver];
[self.textView resignFirstResponder];
[self jsq_resetKeyboardAndTextView];
}
}];
}

View File

@ -21,6 +21,7 @@
#import "JSQMessagesCollectionView.h"
#import "JSQMessagesCollectionViewFlowLayout.h"
#import "JSQMessagesInputToolbar.h"
#import "JSQMessagesKeyboardController.h"
/**
* The `JSQMessagesViewController` class is an abstract class that represents a view controller whose content consists of
@ -33,40 +34,43 @@
UITextViewDelegate>
/**
* Returns the collection view object managed by this view controller.
* Returns the collection view object managed by this view controller.
* This view controller is the collection view's data source and delegate.
*/
@property (weak, nonatomic, readonly) JSQMessagesCollectionView *collectionView;
/**
* Returns the input toolbar view object managed by this view controller.
* Returns the input toolbar view object managed by this view controller.
* This view controller is the toolbar's delegate.
*/
@property (weak, nonatomic, readonly) JSQMessagesInputToolbar *inputToolbar;
/**
* Returns the keyboard controller object used to manage the software keyboard.
*/
@property (strong, nonatomic) JSQMessagesKeyboardController *keyboardController;
/**
* The display name of the current user who is sending messages.
* This value does not have to be unique.
*
* @discussion This value must not be `nil`. The default value is `@"JSQDefaultSender"`.
* @discussion This value does not have to be unique. This value must not be `nil`.
*/
@property (copy, nonatomic) NSString *senderDisplayName;
/**
* The string identifier that uniquely identifies the current user sending messages.
*
*
* @discussion This property is used to determine if a message is incoming or outgoing.
* All message data objects returned by `collectionView:messageDataForItemAtIndexPath:` are
* checked against this identifier.
* This value must not be `nil`. The default value is `@"JSQDefaultSender"`.
* checked against this identifier. This value must not be `nil`.
*/
@property (copy, nonatomic) NSString *senderId;
/**
* Specifies whether or not the view controller should automatically scroll to the most recent message
* Specifies whether or not the view controller should automatically scroll to the most recent message
* when the view appears and when sending, receiving, and composing a new message.
*
* @discussion The default value is `YES`, which allows the view controller to scroll automatically to the most recent message.
* @discussion The default value is `YES`, which allows the view controller to scroll automatically to the most recent message.
* Set to `NO` if you want to manage scrolling yourself.
*/
@property (assign, nonatomic) BOOL automaticallyScrollsToMostRecentMessage;
@ -78,7 +82,7 @@
* @discussion This cell identifier is used for outgoing text message data items.
* The default value is the string returned by `[JSQMessagesCollectionViewCellOutgoing cellReuseIdentifier]`.
* This value must not be `nil`.
*
*
* @see JSQMessagesCollectionViewCellOutgoing.
*
* @warning Overriding this property's default value is *not* recommended.
@ -90,7 +94,7 @@
@property (copy, nonatomic) NSString *outgoingCellIdentifier;
/**
* The collection view cell identifier to use for dequeuing outgoing message collection view cells
* The collection view cell identifier to use for dequeuing outgoing message collection view cells
* in the collectionView for media messages.
*
* @discussion This cell identifier is used for outgoing media message data items.
@ -173,7 +177,7 @@
/**
* Returns the `UINib` object initialized for a `JSQMessagesViewController`.
*
* @return The initialized `UINib` object or `nil` if there were errors during initialization
* @return The initialized `UINib` object or `nil` if there were errors during initialization
* or the nib file could not be located.
*
* @discussion You may override this method to provide a customized nib. If you do,
@ -184,7 +188,7 @@
/**
* Creates and returns a new `JSQMessagesViewController` object.
*
*
* @discussion This is the designated initializer for programmatic instantiation.
*
* @return An initialized `JSQMessagesViewController` object if successful, `nil` otherwise.
@ -264,4 +268,60 @@
*/
- (void)scrollToBottomAnimated:(BOOL)animated;
/**
* Used to decide if a message is incoming or outgoing.
*
* @discussion The default implementation of this method compares the `senderId` of the message to the
* value of the `senderId` property and returns `YES` if they are equal. Subclasses can override
* this method to specialize the decision logic.
*/
- (BOOL)isOutgoingMessage:(id<JSQMessageData>)messageItem;
/**
* Scrolls the collection view so that the cell at the specified indexPath is completely visible above the `inputToolbar`.
*
* @param indexPath The indexPath for the cell that will be visible.
* @param animated Pass `YES` if you want to animate scrolling, `NO` otherwise.
*/
- (void)scrollToIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
/**
Call to super required.
*/
- (void)viewDidLoad NS_REQUIRES_SUPER;
/**
Call to super required.
*/
- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
/**
Call to super required.
*/
- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
/**
Call to super required.
*/
- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
/**
Call to super required.
*/
- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
/**
Called when `UIMenuControllerWillShowMenuNotification` is posted.
@param notification The posted notification.
*/
- (void)didReceiveMenuWillShowNotification:(NSNotification *)notification;
/**
Called when `UIMenuControllerWillHideMenuNotification` is posted.
@param notification The posted notification.
*/
- (void)didReceiveMenuWillHideNotification:(NSNotification *)notification;
@end

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="JSQMessagesViewController">
@ -45,9 +46,4 @@
<nil key="simulatedStatusBarMetrics"/>
</view>
</objects>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View File

@ -21,22 +21,6 @@
#import "UIColor+JSQMessages.h"
@interface JSQMessagesAvatarImageFactory ()
+ (UIImage *)jsq_circularImage:(UIImage *)image
withDiamter:(NSUInteger)diameter
highlightedColor:(UIColor *)highlightedColor;
+ (UIImage *)jsq_imageWitInitials:(NSString *)initials
backgroundColor:(UIColor *)backgroundColor
textColor:(UIColor *)textColor
font:(UIFont *)font
diameter:(NSUInteger)diameter;
@end
@implementation JSQMessagesAvatarImageFactory
#pragma mark - Public
@ -44,9 +28,9 @@
+ (JSQMessagesAvatarImage *)avatarImageWithPlaceholder:(UIImage *)placeholderImage diameter:(NSUInteger)diameter
{
UIImage *circlePlaceholderImage = [JSQMessagesAvatarImageFactory jsq_circularImage:placeholderImage
withDiamter:diameter
withDiameter:diameter
highlightedColor:nil];
return [JSQMessagesAvatarImage avatarImageWithPlaceholder:circlePlaceholderImage];
}
@ -54,7 +38,7 @@
{
UIImage *avatar = [JSQMessagesAvatarImageFactory circularAvatarImage:image withDiameter:diameter];
UIImage *highlightedAvatar = [JSQMessagesAvatarImageFactory circularAvatarHighlightedImage:image withDiameter:diameter];
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatar
highlightedImage:highlightedAvatar
placeholderImage:avatar];
@ -63,14 +47,14 @@
+ (UIImage *)circularAvatarImage:(UIImage *)image withDiameter:(NSUInteger)diameter
{
return [JSQMessagesAvatarImageFactory jsq_circularImage:image
withDiamter:diameter
withDiameter:diameter
highlightedColor:nil];
}
+ (UIImage *)circularAvatarHighlightedImage:(UIImage *)image withDiameter:(NSUInteger)diameter
{
return [JSQMessagesAvatarImageFactory jsq_circularImage:image
withDiamter:diameter
withDiameter:diameter
highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
}
@ -85,11 +69,11 @@
textColor:textColor
font:font
diameter:diameter];
UIImage *avatarHighlightedImage = [JSQMessagesAvatarImageFactory jsq_circularImage:avatarImage
withDiamter:diameter
withDiameter:diameter
highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatarImage
highlightedImage:avatarHighlightedImage
placeholderImage:avatarImage];
@ -108,70 +92,64 @@
NSParameterAssert(textColor != nil);
NSParameterAssert(font != nil);
NSParameterAssert(diameter > 0);
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
NSString *text = [initials uppercaseStringWithLocale:[NSLocale currentLocale]];
NSDictionary *attributes = @{ NSFontAttributeName : font,
NSForegroundColorAttributeName : textColor };
CGRect textFrame = [text boundingRectWithSize:frame.size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributes
context:nil];
CGRect textFrame = [initials boundingRectWithSize:frame.size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributes
context:nil];
CGPoint frameMidPoint = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
CGPoint textFrameMidPoint = CGPointMake(CGRectGetMidX(textFrame), CGRectGetMidY(textFrame));
CGFloat dx = frameMidPoint.x - textFrameMidPoint.x;
CGFloat dy = frameMidPoint.y - textFrameMidPoint.y;
CGPoint drawPoint = CGPointMake(dx, dy);
UIImage *image = nil;
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, frame);
[text drawAtPoint:drawPoint withAttributes:attributes];
[initials drawAtPoint:drawPoint withAttributes:attributes];
image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
}
UIGraphicsEndImageContext();
return [JSQMessagesAvatarImageFactory jsq_circularImage:image withDiamter:diameter highlightedColor:nil];
return [JSQMessagesAvatarImageFactory jsq_circularImage:image withDiameter:diameter highlightedColor:nil];
}
+ (UIImage *)jsq_circularImage:(UIImage *)image withDiamter:(NSUInteger)diameter highlightedColor:(UIColor *)highlightedColor
+ (UIImage *)jsq_circularImage:(UIImage *)image withDiameter:(NSUInteger)diameter highlightedColor:(UIColor *)highlightedColor
{
NSParameterAssert(image != nil);
NSParameterAssert(diameter > 0);
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
UIImage *newImage = nil;
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
UIBezierPath *imgPath = [UIBezierPath bezierPathWithOvalInRect:frame];
[imgPath addClip];
[image drawInRect:frame];
if (highlightedColor != nil) {
CGContextSetFillColorWithColor(context, highlightedColor.CGColor);
CGContextFillEllipseInRect(context, frame);
}
newImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
}
UIGraphicsEndImageContext();

View File

@ -27,14 +27,6 @@
@property (strong, nonatomic, readonly) UIImage *bubbleImage;
@property (assign, nonatomic, readonly) UIEdgeInsets capInsets;
- (UIEdgeInsets)jsq_centerPointEdgeInsetsForImageSize:(CGSize)bubbleImageSize;
- (JSQMessagesBubbleImage *)jsq_messagesBubbleImageWithColor:(UIColor *)color flippedForIncoming:(BOOL)flippedForIncoming;
- (UIImage *)jsq_horizontallyFlippedImageFromImage:(UIImage *)image;
- (UIImage *)jsq_stretchableImageFromImage:(UIImage *)image withCapInsets:(UIEdgeInsets)capInsets;
@end
@ -66,11 +58,6 @@
return [self initWithBubbleImage:[UIImage jsq_bubbleCompactImage] capInsets:UIEdgeInsetsZero];
}
- (void)dealloc
{
_bubbleImage = nil;
}
#pragma mark - Public
- (JSQMessagesBubbleImage *)outgoingMessagesBubbleImageWithColor:(UIColor *)color

View File

@ -61,7 +61,7 @@
* @see JSQMessagesBubbleImageFactory.
* @see JSQMessagesBubbleImage.
*/
- (instancetype)initWithBubbleImageFactory:(JSQMessagesBubbleImageFactory *)bubbleImageFactory;
- (instancetype)initWithBubbleImageFactory:(JSQMessagesBubbleImageFactory *)bubbleImageFactory NS_DESIGNATED_INITIALIZER;
/**
* Applies an outgoing bubble image mask to the specified mediaView.

View File

@ -21,13 +21,6 @@
#import "JSQMessagesBubbleImageFactory.h"
@interface JSQMessagesMediaViewBubbleImageMasker ()
- (void)jsq_maskView:(UIView *)view withImage:(UIImage *)image;
@end
@implementation JSQMessagesMediaViewBubbleImageMasker
#pragma mark - Initialization

View File

@ -66,13 +66,6 @@
return self;
}
- (void)dealloc
{
_dateFormatter = nil;
_dateTextAttributes = nil;
_timeTextAttributes = nil;
}
#pragma mark - Formatter
- (NSString *)timestampForDate:(NSDate *)date

View File

@ -20,6 +20,7 @@
#import "UIColor+JSQMessages.h"
#import "UIImage+JSQMessages.h"
#import "NSBundle+JSQMessages.h"
@implementation JSQMessagesToolbarButtonFactory
@ -29,47 +30,49 @@
UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage];
UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor lightGrayColor]];
UIImage *highlightedImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor darkGrayColor]];
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, accessoryImage.size.width, 32.0f)];
[accessoryButton setImage:normalImage forState:UIControlStateNormal];
[accessoryButton setImage:highlightedImage forState:UIControlStateHighlighted];
accessoryButton.contentMode = UIViewContentModeScaleAspectFit;
accessoryButton.backgroundColor = [UIColor clearColor];
accessoryButton.tintColor = [UIColor lightGrayColor];
accessoryButton.accessibilityLabel = [NSBundle jsq_localizedStringForKey:@"accessory_button_accessibility_label"];
return accessoryButton;
}
+ (UIButton *)defaultSendButtonItem
{
NSString *sendTitle = NSLocalizedStringFromTable(@"Send", @"JSQMessages", @"Text for the send button on the messages view toolbar");
NSString *sendTitle = [NSBundle jsq_localizedStringForKey:@"send"];
UIButton *sendButton = [[UIButton alloc] initWithFrame:CGRectZero];
[sendButton setTitle:sendTitle forState:UIControlStateNormal];
[sendButton setTitleColor:[UIColor jsq_messageBubbleBlueColor] forState:UIControlStateNormal];
[sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted];
[sendButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
sendButton.titleLabel.font = [UIFont boldSystemFontOfSize:17.0f];
sendButton.titleLabel.adjustsFontSizeToFitWidth = YES;
sendButton.titleLabel.minimumScaleFactor = 0.85f;
sendButton.contentMode = UIViewContentModeCenter;
sendButton.backgroundColor = [UIColor clearColor];
sendButton.tintColor = [UIColor jsq_messageBubbleBlueColor];
CGFloat maxHeight = 32.0f;
CGRect sendTitleRect = [sendTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, maxHeight)
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:@{ NSFontAttributeName : sendButton.titleLabel.font }
context:nil];
sendButton.frame = CGRectMake(0.0f,
0.0f,
CGRectGetWidth(CGRectIntegral(sendTitleRect)),
maxHeight);
return sendButton;
}

View File

@ -29,9 +29,12 @@
#import "JSQMessagesLoadEarlierHeaderView.h"
// Layout
#import "JSQMessagesBubbleSizeCalculating.h"
#import "JSQMessagesBubblesSizeCalculator.h"
#import "JSQMessagesCollectionViewFlowLayout.h"
#import "JSQMessagesCollectionViewLayoutAttributes.h"
#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
#import "JSQAudioMediaViewAttributes.h"
// Toolbar
#import "JSQMessagesComposerTextView.h"
@ -42,6 +45,7 @@
#import "JSQMessage.h"
#import "JSQMediaItem.h"
#import "JSQAudioMediaItem.h"
#import "JSQPhotoMediaItem.h"
#import "JSQLocationMediaItem.h"
#import "JSQVideoMediaItem.h"
@ -49,6 +53,8 @@
#import "JSQMessagesBubbleImage.h"
#import "JSQMessagesAvatarImage.h"
#import "JSQAudioMediaViewAttributes.h"
// Protocols
#import "JSQMessageData.h"
#import "JSQMessageMediaData.h"
@ -70,5 +76,6 @@
#import "UIColor+JSQMessages.h"
#import "UIImage+JSQMessages.h"
#import "UIView+JSQMessages.h"
#import "NSBundle+JSQMessages.h"
#endif

View File

@ -0,0 +1,117 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
An instance of `JSQAudioMediaViewAttributes` specifies the appearance configuration of a `JSQAudioMediaItem`.
Use this class to customize the appearance of `JSQAudioMediaItem`.
*/
@interface JSQAudioMediaViewAttributes : NSObject
/**
* The image for the play button. The default is a play icon.
*/
@property (nonatomic, strong) UIImage *playButtonImage;
/**
* The image for the pause button. The default is a pause icon.
*/
@property (nonatomic, strong) UIImage *pauseButtonImage;
/**
* The font for the elapsed time label. The default is a system font.
*/
@property (strong, nonatomic) UIFont *labelFont;
/**
* Specifies whether to show fractions of a second for audio files with a duration of less than 1 minute.
*/
@property (nonatomic, assign) BOOL showFractionalSeconds;
/**
* The background color for the player.
*/
@property (nonatomic, strong) UIColor *backgroundColor;
/**
* The tint color for the player.
*/
@property (nonatomic, strong) UIColor *tintColor;
/**
* Insets that sepcify the padding around the play/pause button and time label.
*/
@property (nonatomic, assign) UIEdgeInsets controlInsets;
/**
* Specifies the padding between the button, progress bar, and label.
*/
@property (nonatomic, assign) CGFloat controlPadding;
/**
* Specifies the audio category set prior to playback.
*/
@property (nonatomic, copy) NSString *audioCategory;
/**
* Specifies the audio category options set prior to playback.
*/
@property (nonatomic) AVAudioSessionCategoryOptions audioCategoryOptions;
/**
Initializes and returns a `JSQAudioMediaViewAttributes` instance having the specified attributes.
@param playButtonImage The image for the play button.
@param pauseButtonImage The image for the pause button.
@param labelFont The font for the elapsed time label.
@param showFractionalSeconds Specifies whether to show fractions of a second for audio files with a duration of less than 1 minute.
@param backgroundColor The background color for the player.
@param tintColor The tint color for the player.
@param controlInsets Insets that sepcify the padding around the play/pause button and time label.
@param controlPadding Specifies the padding between the button, progress bar, and label.
@param audioCategory Specifies the audio category set prior to playback.
@param audioCategoryOptions Specifies the audio category options set prior to playback.
@return A new `JSQAudioMediaViewAttributes` instance
*/
- (instancetype)initWithPlayButtonImage:(UIImage *)playButtonImage
pauseButtonImage:(UIImage *)pauseButtonImage
labelFont:(UIFont *)labelFont
showFractionalSecodns:(BOOL)showFractionalSeconds
backgroundColor:(UIColor *)backgroundColor
tintColor:(UIColor *)tintColor
controlInsets:(UIEdgeInsets)controlInsets
controlPadding:(CGFloat)controlPadding
audioCategory:(NSString *)audioCategory
audioCategoryOptions:(AVAudioSessionCategoryOptions)audioCategoryOptions NS_DESIGNATED_INITIALIZER;
/**
Initializes and returns a default `JSQAudioMediaViewAttributes` instance.
@return A new `JSQAudioMediaViewAttributes` instance
*/
- (instancetype)init;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,114 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import "JSQAudioMediaViewAttributes.h"
#import "UIImage+JSQMessages.h"
#import "UIColor+JSQMessages.h"
@implementation JSQAudioMediaViewAttributes
- (instancetype)initWithPlayButtonImage:(UIImage *)playButtonImage
pauseButtonImage:(UIImage *)pauseButtonImage
labelFont:(UIFont *)labelFont
showFractionalSecodns:(BOOL)showFractionalSeconds
backgroundColor:(UIColor *)backgroundColor
tintColor:(UIColor *)tintColor
controlInsets:(UIEdgeInsets)controlInsets
controlPadding:(CGFloat)controlPadding
audioCategory:(NSString *)audioCategory
audioCategoryOptions:(AVAudioSessionCategoryOptions)audioCategoryOptions {
NSParameterAssert(playButtonImage != nil);
NSParameterAssert(pauseButtonImage != nil);
NSParameterAssert(labelFont != nil);
NSParameterAssert(backgroundColor != nil);
NSParameterAssert(tintColor != nil);
NSParameterAssert(audioCategory != nil);
self = [super init];
if (self) {
_playButtonImage = playButtonImage;
_pauseButtonImage = pauseButtonImage;
_labelFont = labelFont;
_showFractionalSeconds = showFractionalSeconds;
_backgroundColor = backgroundColor;
_tintColor = tintColor;
_controlInsets = controlInsets;
_controlPadding = controlPadding;
_audioCategory = audioCategory;
_audioCategoryOptions = audioCategoryOptions;
}
return self;
}
- (instancetype)init
{
UIColor *tintColor = [UIColor jsq_messageBubbleBlueColor];
AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionDuckOthers
| AVAudioSessionCategoryOptionDefaultToSpeaker
| AVAudioSessionCategoryOptionAllowBluetooth;
return [self initWithPlayButtonImage:[[UIImage jsq_defaultPlayImage] jsq_imageMaskedWithColor:tintColor]
pauseButtonImage:[[UIImage jsq_defaultPauseImage] jsq_imageMaskedWithColor:tintColor]
labelFont:[UIFont systemFontOfSize:12]
showFractionalSecodns:NO
backgroundColor:[UIColor jsq_messageBubbleLightGrayColor]
tintColor:tintColor
controlInsets:UIEdgeInsetsMake(6, 6, 6, 18)
controlPadding:6
audioCategory:@"AVAudioSessionCategoryPlayback"
audioCategoryOptions:options];
}
- (void)setPlayButtonImage:(UIImage *)playButtonImage
{
NSParameterAssert(playButtonImage != nil);
_playButtonImage = playButtonImage;
}
- (void)setPauseButtonImage:(UIImage *)pauseButtonImage
{
NSParameterAssert(pauseButtonImage != nil);
_pauseButtonImage = pauseButtonImage;
}
- (void)setLabelFont:(UIFont *)labelFont
{
NSParameterAssert(labelFont != nil);
_labelFont = labelFont;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
NSParameterAssert(backgroundColor != nil);
_backgroundColor = backgroundColor;
}
- (void)setTintColor:(UIColor *)tintColor
{
NSParameterAssert(tintColor != nil);
_tintColor = tintColor;
}
- (void)setAudioCategory:(NSString *)audioCategory
{
NSParameterAssert(audioCategory != nil);
_audioCategory = audioCategory;
}
@end

View File

@ -0,0 +1,57 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class JSQMessagesCollectionViewFlowLayout;
@protocol JSQMessageData;
/**
* The `JSQMessagesBubbleSizeCalculating` protocol defines the common interface through which
* an object provides layout information to an instance of `JSQMessagesCollectionViewFlowLayout`.
*
* A concrete class that conforms to this protocol is provided in the library.
* See `JSQMessagesBubbleSizeCalculator`.
*/
@protocol JSQMessagesBubbleSizeCalculating <NSObject>
/**
* Computes and returns the size of the `messageBubbleImageView` property
* of a `JSQMessagesCollectionViewCell` for the specified messageData at indexPath.
*
* @param messageData A message data object.
* @param indexPath The index path at which messageData is located.
* @param layout The layout object asking for this information.
*
* @return A sizes that specifies the required dimensions to display the entire message contents.
* Note, this is *not* the entire cell, but only its message bubble.
*/
- (CGSize)messageBubbleSizeForMessageData:(id<JSQMessageData>)messageData
atIndexPath:(NSIndexPath *)indexPath
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
/**
* Notifies the receiver that the layout will be reset.
* Use this method to clear any cached layout information, if necessary.
*
* @param layout The layout object notifying the receiver.
*/
- (void)prepareForResettingLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
@end

View File

@ -0,0 +1,43 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import <Foundation/Foundation.h>
#import "JSQMessagesBubbleSizeCalculating.h"
/**
* An instance of `JSQMessagesBubblesSizeCalculator` is responsible for calculating
* message bubble sizes for an instance of `JSQMessagesCollectionViewFlowLayout`.
*/
@interface JSQMessagesBubblesSizeCalculator : NSObject <JSQMessagesBubbleSizeCalculating>
/**
* Initializes and returns a bubble size calculator with the given cache and minimumBubbleWidth.
*
* @param cache A cache object used to store layout information.
* @param minimumBubbleWidth The minimum width for any given message bubble.
* @param usesFixedWidthBubbles Specifies whether or not to use fixed-width bubbles.
* If `NO` (the default), then bubbles will resize when rotating to landscape.
*
* @return An initialized `JSQMessagesBubblesSizeCalculator` object if successful, `nil` otherwise.
*/
- (instancetype)initWithCache:(NSCache *)cache
minimumBubbleWidth:(NSUInteger)minimumBubbleWidth
usesFixedWidthBubbles:(BOOL)usesFixedWidthBubbles NS_DESIGNATED_INITIALIZER;
@end

View File

@ -0,0 +1,179 @@
//
// Created by Jesse Squires
// http://www.jessesquires.com
//
//
// Documentation
// http://cocoadocs.org/docsets/JSQMessagesViewController
//
//
// GitHub
// https://github.com/jessesquires/JSQMessagesViewController
//
//
// License
// Copyright (c) 2014 Jesse Squires
// Released under an MIT license: http://opensource.org/licenses/MIT
//
#import "JSQMessagesBubblesSizeCalculator.h"
#import "JSQMessagesCollectionView.h"
#import "JSQMessagesCollectionViewDataSource.h"
#import "JSQMessagesCollectionViewFlowLayout.h"
#import "JSQMessageData.h"
#import "UIImage+JSQMessages.h"
@interface JSQMessagesBubblesSizeCalculator ()
@property (strong, nonatomic, readonly) NSCache *cache;
@property (assign, nonatomic, readonly) NSUInteger minimumBubbleWidth;
@property (assign, nonatomic, readonly) BOOL usesFixedWidthBubbles;
@property (assign, nonatomic, readonly) NSInteger additionalInset;
@property (assign, nonatomic) CGFloat layoutWidthForFixedWidthBubbles;
@end
@implementation JSQMessagesBubblesSizeCalculator
#pragma mark - Init
- (instancetype)initWithCache:(NSCache *)cache
minimumBubbleWidth:(NSUInteger)minimumBubbleWidth
usesFixedWidthBubbles:(BOOL)usesFixedWidthBubbles
{
NSParameterAssert(cache != nil);
NSParameterAssert(minimumBubbleWidth > 0);
self = [super init];
if (self) {
_cache = cache;
_minimumBubbleWidth = minimumBubbleWidth;
_usesFixedWidthBubbles = usesFixedWidthBubbles;
_layoutWidthForFixedWidthBubbles = 0.0f;
// this extra inset value is needed because `boundingRectWithSize:` is slightly off
// see comment below
_additionalInset = 2;
}
return self;
}
- (instancetype)init
{
NSCache *cache = [NSCache new];
cache.name = @"JSQMessagesBubblesSizeCalculator.cache";
cache.countLimit = 200;
return [self initWithCache:cache
minimumBubbleWidth:[UIImage jsq_bubbleCompactImage].size.width
usesFixedWidthBubbles:NO];
}
#pragma mark - NSObject
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: cache=%@, minimumBubbleWidth=%@ usesFixedWidthBubbles=%@>",
[self class], self.cache, @(self.minimumBubbleWidth), @(self.usesFixedWidthBubbles)];
}
#pragma mark - JSQMessagesBubbleSizeCalculating
- (void)prepareForResettingLayout:(JSQMessagesCollectionViewFlowLayout *)layout
{
[self.cache removeAllObjects];
}
- (CGSize)messageBubbleSizeForMessageData:(id<JSQMessageData>)messageData
atIndexPath:(NSIndexPath *)indexPath
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
{
NSValue *cachedSize = [self.cache objectForKey:@([messageData messageHash])];
if (cachedSize != nil) {
return [cachedSize CGSizeValue];
}
CGSize finalSize = CGSizeZero;
if ([messageData isMediaMessage]) {
finalSize = [[messageData media] mediaViewDisplaySize];
}
else {
CGSize avatarSize = [self jsq_avatarSizeForMessageData:messageData withLayout:layout];
// from the cell xibs, there is a 2 point space between avatar and bubble
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
CGFloat horizontalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.left + layout.messageBubbleTextViewTextContainerInsets.right;
CGFloat horizontalFrameInsets = layout.messageBubbleTextViewFrameInsets.left + layout.messageBubbleTextViewFrameInsets.right;
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - avatarSize.width - layout.messageBubbleLeftRightMargin - horizontalInsetsTotal;
CGRect stringRect = [[messageData text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName : layout.messageBubbleFont }
context:nil];
CGSize stringSize = CGRectIntegral(stringRect).size;
CGFloat verticalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.top + layout.messageBubbleTextViewTextContainerInsets.bottom;
CGFloat verticalFrameInsets = layout.messageBubbleTextViewFrameInsets.top + layout.messageBubbleTextViewFrameInsets.bottom;
// add extra 2 points of space (`self.additionalInset`), because `boundingRectWithSize:` is slightly off
// not sure why. magix. (shrug) if you know, submit a PR
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + self.additionalInset;
// same as above, an extra 2 points of magix
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.minimumBubbleWidth) + self.additionalInset;
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
}
[self.cache setObject:[NSValue valueWithCGSize:finalSize] forKey:@([messageData messageHash])];
return finalSize;
}
- (CGSize)jsq_avatarSizeForMessageData:(id<JSQMessageData>)messageData
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
{
NSString *messageSender = [messageData senderId];
if ([messageSender isEqualToString:[layout.collectionView.dataSource senderId]]) {
return layout.outgoingAvatarViewSize;
}
return layout.incomingAvatarViewSize;
}
- (CGFloat)textBubbleWidthForLayout:(JSQMessagesCollectionViewFlowLayout *)layout
{
if (self.usesFixedWidthBubbles) {
return [self widthForFixedWidthBubblesWithLayout:layout];
}
return layout.itemWidth;
}
- (CGFloat)widthForFixedWidthBubblesWithLayout:(JSQMessagesCollectionViewFlowLayout *)layout {
if (self.layoutWidthForFixedWidthBubbles > 0.0f) {
return self.layoutWidthForFixedWidthBubbles;
}
// also need to add `self.additionalInset` here, see comment above
NSInteger horizontalInsets = layout.sectionInset.left + layout.sectionInset.right + self.additionalInset;
CGFloat width = CGRectGetWidth(layout.collectionView.bounds) - horizontalInsets;
CGFloat height = CGRectGetHeight(layout.collectionView.bounds) - horizontalInsets;
self.layoutWidthForFixedWidthBubbles = MIN(width, height);
return self.layoutWidthForFixedWidthBubbles;
}
@end

View File

@ -23,6 +23,8 @@
#import <UIKit/UIKit.h>
#import "JSQMessagesBubbleSizeCalculating.h"
@class JSQMessagesCollectionView;
@ -56,7 +58,18 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault;
/**
* The collection view object currently using this layout object.
*/
// TODO: fix, rename "messagesCollectionView", see #920
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-property-type"
@property (readonly, nonatomic) JSQMessagesCollectionView *collectionView;
#pragma clang diagnostic pop
/**
* The object that the layout uses to calculate bubble sizes.
* The default value is an instance of `JSQMessagesBubblesSizeCalculator`.
*/
@property (strong, nonatomic) id<JSQMessagesBubbleSizeCalculating> bubbleSizeCalculator;
/**
* Specifies whether or not the layout should enable spring behavior dynamics for its items using `UIDynamics`.
@ -176,12 +189,15 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault;
/**
* Computes and returns the size of the `messageBubbleImageView` property of a `JSQMessagesCollectionViewCell`
* at the specified indexPath. The returned size contains the required dimensions to display the entire message contents.
* Note, this is *not* the entire cell, but only its message bubble.
* at the specified indexPath.
*
* @param indexPath The index path of the item to be displayed.
*
* @return The size of the message bubble for the item displayed at indexPath.
*
* @discussion The layout uses its `bubbleSizeCalculator` object to perform this computation.
* The returned size contains the required dimensions to display the entire message contents.
* Note, this is *not* the entire cell, but only its message bubble.
*/
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath;

View File

@ -30,6 +30,7 @@
#import "JSQMessagesCollectionViewLayoutAttributes.h"
#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
#import "JSQMessagesBubblesSizeCalculator.h"
#import "UIImage+JSQMessages.h"
@ -40,37 +41,21 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
@interface JSQMessagesCollectionViewFlowLayout ()
@property (strong, nonatomic) NSCache *messageBubbleCache;
@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
@property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
@property (assign, nonatomic) CGFloat latestDelta;
@property (assign, nonatomic, readonly) NSUInteger bubbleImageAssetWidth;
- (void)jsq_configureFlowLayout;
- (void)jsq_didReceiveApplicationMemoryWarningNotification:(NSNotification *)notification;
- (void)jsq_didReceiveDeviceOrientationDidChangeNotification:(NSNotification *)notification;
- (void)jsq_resetLayout;
- (void)jsq_resetDynamicAnimator;
- (void)jsq_configureMessageCellLayoutAttributes:(JSQMessagesCollectionViewLayoutAttributes *)layoutAttributes;
- (CGSize)jsq_avatarSizeForIndexPath:(NSIndexPath *)indexPath;
- (UIAttachmentBehavior *)jsq_springBehaviorWithLayoutAttributesItem:(UICollectionViewLayoutAttributes *)item;
- (void)jsq_addNewlyVisibleBehaviorsFromVisibleItems:(NSArray *)visibleItems;
- (void)jsq_removeNoLongerVisibleBehaviorsFromVisibleItemsIndexPaths:(NSSet *)visibleItemsIndexPaths;
- (void)jsq_adjustSpringBehavior:(UIAttachmentBehavior *)springBehavior forTouchLocation:(CGPoint)touchLocation;
@end
@implementation JSQMessagesCollectionViewFlowLayout
@dynamic collectionView;
@synthesize bubbleSizeCalculator = _bubbleSizeCalculator;
#pragma mark - Initialization
- (void)jsq_configureFlowLayout
@ -79,12 +64,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
self.sectionInset = UIEdgeInsetsMake(10.0f, 4.0f, 10.0f, 4.0f);
self.minimumLineSpacing = 4.0f;
_bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width;
_messageBubbleCache = [NSCache new];
_messageBubbleCache.name = @"JSQMessagesCollectionViewFlowLayout.messageBubbleCache";
_messageBubbleCache.countLimit = 200;
_messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
@ -143,21 +122,16 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
_messageBubbleFont = nil;
[_messageBubbleCache removeAllObjects];
_messageBubbleCache = nil;
[_dynamicAnimator removeAllBehaviors];
_dynamicAnimator = nil;
[_visibleIndexPaths removeAllObjects];
_visibleIndexPaths = nil;
}
#pragma mark - Setters
- (void)setBubbleSizeCalculator:(id<JSQMessagesBubbleSizeCalculating>)bubbleSizeCalculator
{
NSParameterAssert(bubbleSizeCalculator != nil);
_bubbleSizeCalculator = bubbleSizeCalculator;
}
- (void)setSpringinessEnabled:(BOOL)springinessEnabled
{
if (_springinessEnabled == springinessEnabled) {
@ -221,11 +195,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
[self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
}
- (void)setCacheLimit:(NSUInteger)cacheLimit
{
self.messageBubbleCache.countLimit = cacheLimit;
}
#pragma mark - Getters
- (CGFloat)itemWidth
@ -249,9 +218,13 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
return _visibleIndexPaths;
}
- (NSUInteger)cacheLimit
- (id<JSQMessagesBubbleSizeCalculating>)bubbleSizeCalculator
{
return self.messageBubbleCache.countLimit;
if (_bubbleSizeCalculator == nil) {
_bubbleSizeCalculator = [JSQMessagesBubblesSizeCalculator new];
}
return _bubbleSizeCalculator;
}
#pragma mark - Notifications
@ -281,7 +254,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
[self jsq_resetDynamicAnimator];
}
if (context.emptyCache) {
if (context.invalidateFlowLayoutMessagesCache) {
[self jsq_resetLayout];
}
@ -308,7 +281,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attributesInRect = [super layoutAttributesForElementsInRect:rect];
NSArray *attributesInRect = [[super layoutAttributesForElementsInRect:rect] copy];
if (self.springinessEnabled) {
NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy];
@ -329,7 +302,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
}
}
attributesInRect = attributesInRectCopy;
attributesInRect = [attributesInRectCopy copy];
}
[attributesInRect enumerateObjectsUsingBlock:^(JSQMessagesCollectionViewLayoutAttributes *attributesItem, NSUInteger idx, BOOL *stop) {
@ -337,7 +310,53 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
[self jsq_configureMessageCellLayoutAttributes:attributesItem];
}
else {
attributesItem.zIndex = -1;
// BEGIN HACK for Signal to fix scrolling crash.
//
// Signature of crash looks like this:
//
// 0 CoreFoundation 0x18cbe2fe0 __exceptionPreprocess + 124 (NSException.m:165)
// 1 libobjc.A.dylib 0x18b644538 objc_exception_throw + 56 (objc-exception.mm:521)
// 2 CoreFoundation 0x18cbe2eb4 +[NSException raise:format:arguments:] + 104 (NSException.m:131)
// 3 Foundation 0x18d67b760 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 112 (NSException.m:157)
// 4 UIKit 0x192d715c8 __45-[UICollectionViewData validateLayoutInRect:]_block_invoke + 1328 (UICollectionViewData.m:445)
// 5 UIKit 0x192d70ad4 -[UICollectionViewData validateLayoutInRect:] + 1496 (UICollectionViewData.m:559)
// 6 UIKit 0x193653184 -[UICollectionViewData layoutAttributesForCellsInRect:validateLayout:] + 148 (UICollectionViewData.m:885)
// 7 UIKit 0x19360f9f4 -[UICollectionView _computePrefetchCandidatesForVisibleBounds:futureVisibleBounds:prefetchVector:notifyDelegateIfNeeded:] + 132 (UICollectionView.m:2366)
// 8 UIKit 0x19360f954 -[UICollectionView _computePrefetchCandidatesForVelocity:notifyDelegateIfNeeded:] + 168 (UICollectionView.m:2361)
// 9 UIKit 0x19360f884 -[UICollectionView _prefetchItemsForVelocity:maxItemsToPrefetch:invalidateCandidatesOnDirectionChanges:] + 768 (UICollectionView.m:2308)
// 10 UIKit 0x192d701ac -[UICollectionView layoutSubviews] + 704 (UICollectionView.m:3586)
//
//
// Digging in a bit I can reliably reproduce the crash after ~10-30s of scrolling wildly while
// receiving messages (1/s). The failed assertion is:
//
// I verified that the problem goes away if we remove the "load earlier messages" supplemental view.
//
// For some reason, since prefetching was introduced in iOS10, this became more common.
//
// Another recent change in Signal wherein we're more aggressively invalidating our layout also made
// the occurrences of this crash jump.
//
// The actual assertion failure is like:
//
// layout attributes for supplementary item at index path (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) changed from <JSQMessagesCollectionViewLayoutAttributes: 0x10ab8e860> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 375 32); zIndex = 10; to <JSQMessagesCollectionViewLayoutAttributes: 0x10bc398f0> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 375 32); zIndex = -1; without invalidating the layout
//
// Note the zIndex "changed" from 10 -> -1. This is the only place we touch the zIndex.
//
// The following line was introduced:
//
// commit 2c39325220e63535bc1a79b2d471e6c2e9d3d2a4
// Author: Jesse Squires <jesse.d.squires@gmail.com>
// Date: Mon Jul 21 23:08:17 2014 -0700
//
// fix issue where header/footer failed to appear when springiness is enabled. close #409
//
// Since we're not using "springiness" we should be safe in disabling this.
// (Here's the actual code being commented out)
// attributesItem.zIndex = -1;
// END HACK for Signal to fix scrolling crash.
}
}];
@ -346,7 +365,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)[super layoutAttributesForItemAtIndexPath:indexPath];
JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)[[super layoutAttributesForItemAtIndexPath:indexPath] copy];
if (customAttributes.representedElementCategory == UICollectionElementCategoryCell) {
[self jsq_configureMessageCellLayoutAttributes:customAttributes];
@ -415,7 +434,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (void)jsq_resetLayout
{
[self.messageBubbleCache removeAllObjects];
[self.bubbleSizeCalculator prepareForResettingLayout:self];
[self jsq_resetDynamicAnimator];
}
@ -431,52 +450,12 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
NSValue *cachedSize = [self.messageBubbleCache objectForKey:@(messageItem.hash)];
if (cachedSize != nil) {
return [cachedSize CGSizeValue];
}
CGSize finalSize = CGSizeZero;
if ([messageItem isMediaMessage]) {
finalSize = [[messageItem media] mediaViewDisplaySize];
}
else {
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
// from the cell xibs, there is a 2 point space between avatar and bubble
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal;
CGRect stringRect = [[messageItem text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName : self.messageBubbleFont }
context:nil];
CGSize stringSize = CGRectIntegral(stringRect).size;
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
// add extra 2 points of space, because `boundingRectWithSize:` is slightly off
// not sure why. magix. (shrug) if you know, submit a PR
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + 2.0f;
// same as above, an extra 2 points of magix
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.bubbleImageAssetWidth) + 2.0f;
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
}
[self.messageBubbleCache setObject:[NSValue valueWithCGSize:finalSize] forKey:@(messageItem.hash)];
return finalSize;
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView
messageDataForItemAtIndexPath:indexPath];
return [self.bubbleSizeCalculator messageBubbleSizeForMessageData:messageItem
atIndexPath:indexPath
withLayout:self];
}
- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
@ -523,22 +502,15 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
heightForCellBottomLabelAtIndexPath:indexPath];
}
- (CGSize)jsq_avatarSizeForIndexPath:(NSIndexPath *)indexPath
{
id<JSQMessageData> messageData = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
NSString *messageSender = [messageData senderId];
if ([messageSender isEqualToString:[self.collectionView.dataSource senderId]]) {
return self.outgoingAvatarViewSize;
}
return self.incomingAvatarViewSize;
}
#pragma mark - Spring behavior utilities
- (UIAttachmentBehavior *)jsq_springBehaviorWithLayoutAttributesItem:(UICollectionViewLayoutAttributes *)item
{
if (CGSizeEqualToSize(item.frame.size, CGSizeZero)) {
// adding a spring behavior with zero size will fail in in -prepareForCollectionViewUpdates:
return nil;
}
UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center];
springBehavior.length = 1.0f;
springBehavior.damping = 1.0f;
@ -570,14 +542,14 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
NSArray *behaviors = self.dynamicAnimator.behaviors;
NSIndexSet *indexSet = [behaviors indexesOfObjectsPassingTest:^BOOL(UIAttachmentBehavior *springBehaviour, NSUInteger index, BOOL *stop) {
UICollectionViewLayoutAttributes *layoutAttributes = [springBehaviour.items firstObject];
UICollectionViewLayoutAttributes *layoutAttributes = (UICollectionViewLayoutAttributes *)[springBehaviour.items firstObject];
return ![visibleItemsIndexPaths containsObject:layoutAttributes.indexPath];
}];
NSArray *behaviorsToRemove = [self.dynamicAnimator.behaviors objectsAtIndexes:indexSet];
[behaviorsToRemove enumerateObjectsUsingBlock:^(UIAttachmentBehavior *springBehaviour, NSUInteger index, BOOL *stop) {
UICollectionViewLayoutAttributes *layoutAttributes = [springBehaviour.items firstObject];
UICollectionViewLayoutAttributes *layoutAttributes = (UICollectionViewLayoutAttributes *)[springBehaviour.items firstObject];
[self.dynamicAnimator removeBehavior:springBehaviour];
[self.visibleIndexPaths removeObject:layoutAttributes.indexPath];
}];
@ -585,12 +557,12 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (void)jsq_adjustSpringBehavior:(UIAttachmentBehavior *)springBehavior forTouchLocation:(CGPoint)touchLocation
{
UICollectionViewLayoutAttributes *item = [springBehavior.items firstObject];
UICollectionViewLayoutAttributes *item = (UICollectionViewLayoutAttributes *)[springBehavior.items firstObject];
CGPoint center = item.center;
// if touch is not (0,0) -- adjust item center "in flight"
if (!CGPointEqualToPoint(CGPointZero, touchLocation)) {
CGFloat distanceFromTouch = fabsf(touchLocation.y - springBehavior.anchorPoint.y);
CGFloat distanceFromTouch = fabs(touchLocation.y - springBehavior.anchorPoint.y);
CGFloat scrollResistance = distanceFromTouch / self.springResistanceFactor;
if (self.latestDelta < 0.0f) {

View File

@ -28,10 +28,10 @@
@interface JSQMessagesCollectionViewFlowLayoutInvalidationContext : UICollectionViewFlowLayoutInvalidationContext
/**
* A boolean indicating whether to empty the layout information cache for items and views in the layout.
* A boolean indicating whether to empty the messages layout information cache for items and views in the layout.
* The default value is `NO`.
*/
@property (nonatomic, assign) BOOL emptyCache;
@property (nonatomic, assign) BOOL invalidateFlowLayoutMessagesCache;
/**
* Creates and returns a new `JSQMessagesCollectionViewFlowLayoutInvalidationContext` object.

View File

@ -28,7 +28,7 @@
if (self) {
self.invalidateFlowLayoutDelegateMetrics = NO;
self.invalidateFlowLayoutAttributes = NO;
_emptyCache = NO;
_invalidateFlowLayoutMessagesCache = NO;
}
return self;
}
@ -45,8 +45,8 @@
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, emptyCache=%@>",
[self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.emptyCache)];
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, invalidateFlowLayoutMessagesCache=%@>",
[self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.invalidateFlowLayoutMessagesCache)];
}
@end

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